물 흐름의 맵을 분할


17

이것은 Palantir Technologies의 인터뷰에서 인터넷에 대한 도전입니다 .

농민 그룹은 일부 고도 데이터를 가지고 있으며, 농지에 강우가 흐르는 방식을 이해하도록 도울 것입니다. 우리는 땅을 2 차원의 고도 배열로 나타내고 물이 내리막 길이라는 아이디어에 따라 다음 모델을 사용합니다.

셀의 4 개의 인접 셀이 모두 높은 고도를 갖는 경우이 셀을 싱크라고합니다. 물이 싱크대에 모입니다. 그렇지 않으면 물이 가장 낮은 고도로 인접한 셀로 흐릅니다. 셀이 싱크가 아닌 경우 고유 한 가장 낮은 이웃이 있고이 이웃이 셀보다 낮을 것이라고 가정 할 수 있습니다.

동일한 싱크로 직접 또는 간접적으로 배출되는 셀은 동일한 분지의 일부라고합니다.

당신의 도전은지도를 분지로 분할하는 것입니다. 특히 고도지도가 제공되면 코드에서지도를 분지로 분할하고 분지의 크기를 내림차순으로 출력해야합니다.

고도지도가 정사각형이라고 가정합니다. 입력은 하나의 정수 S,지도의 높이 (및 너비)가있는 줄로 시작합니다. 다음 S 행은 각각 맵의 행을 포함하며, 각 행에는 S 정수 (행의 S 셀 고도)가 있습니다. 일부 농민은 아래 예와 같이 작은 토지를 가지고 있지만 일부 농민은 더 큰 음모를 가지고 있습니다. 그러나 어떤 경우에도 농부는 S = 5000보다 큰 토지의 음모를 가지지 않을 것입니다.

코드는 공백으로 구분 된 분지 크기 목록을 내림차순으로 출력해야합니다. 후행 공백은 무시됩니다.

몇 가지 예는 다음과 같습니다.

입력:

3
1 5 2
2 4 7
3 6 9 

산출: 7 2

A와 B로 표시된 분지는 다음과 같습니다.

A A B
A A B
A A A 

입력:

1
10

산출: 1

이 경우 유역은 하나뿐입니다.

입력:

5
1 0 2 5 8
2 3 4 7 9
3 5 7 8 9
1 2 5 4 2
3 3 5 2 1 

산출: 11 7 7

A, B 및 C로 표시된 분지는 다음과 같습니다.

A A A A A
A A A A A
B B A C C
B B B C C
B B C C C 

입력:

4
0 2 1 3
2 1 0 4
3 3 3 3
5 5 2 1 

산출: 7 5 4

A, B 및 C로 표시된 분지는 다음과 같습니다.

A A B B
A B B B
A B B C
A C C C

1
이 사이트에보다 적합하도록 귀하의 질문을 편집했습니다. 이전에는 프로그래밍 질문 / 코드 검토였습니다. 이제는 도전의 형태입니다. 이 사이트는 커뮤니티가 시도 할 수있는 코드 문제 / 문제를 공개하기위한 것입니다. 참고 : 여전히 승리 기준이 필요합니다. 가장 짧은 코드 ( code-golf )가 권장됩니다.
Justin

2
@OP 여러 가지 대안적인 골프 솔루션 대신 원래 질문에 대한 답변을 원한다면 Stack Overflow (또는 코드 검토?)에서 다시 질문하는 것이 좋습니다.
Gareth

1
@ JanDvorak Code Review에서 편집하기 전에 원래의 질문이 괜찮을 것이라고 생각합니다 (시작하는 골프는 없었습니다)? 그래도 당신은 아마 맞습니다.
Gareth

1
@ JanDvorak 나는 그것을 편집하고 그것을 유효한 코드 골프로 만들 것 같아요
Justin

1
코드 리뷰에 문제를 게시했습니다 -codereview.stackexchange.com/questions/39895/…
AnkitSablok

답변:


8

매스 매 티카

분지 크기 목록을 얻을 수 있습니다

WatershedComponents[
 Image[Rest@ImportString[m,"Table"]] // ImageAdjust,
 CornerNeighbors -> False,
 Method -> "Basins"
 ] // Reverse@Sort@Part[Tally[Flatten@#], All, 2] &

m주어진 입력 데이터는 어디에 있습니까 ? 대체 할 수있는 질문 한 것과 같은 매트릭스를 표시하려면 // Reverse@Sort@Part[Tally[Flatten@#], All, 2] &/. {1 -> "A", 2 -> "B", 3 -> "C"} // MatrixForm또는 하나의 이미지가 사용하는 대신로 표시 할 수 있습니다 //ImageAdjust//Image.


우리를 매달아 두지 마십시오! 정렬 된 분지 크기 목록은 BinCounts [] & Sort []를 사용합니다.
Scott Leadley

@ScottLeadley 요청한 분지 크기 목록이라는 것을 몰랐습니다. 지적 해 주셔서 감사합니다. 답변을 수정했습니다 (마지막 부분이 훨씬 짧아 질 수는 있지만).

2

자바 스크립트 - 673 707 730 751

e=[],g=[],h=[],m=[],q=[];function r(){a=s,b=t;function d(d,A){n=a+d,p=b+A;c>e[n][p]&&(u=!1,v>e[n][p]&&(v=e[n][p],w=n,k=p))}c=e[a][b],u=!0,v=c,w=a,k=b;0!=a&&d(-1,0);a!=l&&d(1,0);0!=b&&d(0,-1);b!=l&&d(0,1);g[a][b]=w;h[a][b]=k;return u}function x(a,b,d){function c(a,b,c,k){g[a+b][c+k]==a&&h[a+b][c+k]==c&&(d=x(a+b,c+k,d))}d++;0!=a&&c(a,-1,b,0);a!=l&&c(a,1,b,0);0!=b&&c(a,0,b,-1);b!=l&&c(a,0,b,1);return d}y=$EXEC('cat "'+$ARG[0]+'"').split("\n");l=y[0]-1;for(z=-1;z++<l;)e[z]=y[z+1].split(" "),g[z]=[],h[z]=[];for(s=-1;s++<l;)for(t=-1;t++<l;)r()&&m.push([s,t]);for(z=m.length-1;0<=z;--z)s=m[z][0],t=m[z][1],q.push(x(s,t,0));print(q.sort(function(a,b){return b-a}).join(" "));

테스트 결과 (Nashorn 사용) :

$ for i in A B C D; do jjs -scripting minlm.js -- "test$i"; done
7 2
1
11 7 7
7 5 4
$

5000 크기의 맵에는 스택 문제가있을 수 있습니다 (그러나 구현 세부 사항입니다).

모든 것에 대한 축소되지 않은 출처는 모호함입니다.

// lm.js - find the local minima


//  Globalization of variables.

/*
    The map is a 2 dimensional array. Indices for the elements map as:

    [0,0] ... [0,n]
    ...
    [n,0] ... [n,n]

Each element of the array is a structure. The structure for each element is:

Item    Purpose         Range       Comment
----    -------         -----       -------
h   Height of cell      integers
s   Is it a sink?       boolean
x   X of downhill cell  (0..maxIndex)   if s is true, x&y point to self
y   Y of downhill cell  (0..maxIndex)

Debugging only:
b   Basin name      ('A'..'A'+# of basins)

Use a separate array-of-arrays for each structure item. The index range is
0..maxIndex.
*/
var height = [];
var sink = [];
var downhillX = [];
var downhillY = [];
//var basin = [];
var maxIndex;

//  A list of sinks in the map. Each element is an array of [ x, y ], where
// both x & y are in the range 0..maxIndex.
var basinList = [];

//  An unordered list of basin sizes.
var basinSize = [];


//  Functions.

function isSink(x,y) {
    var myHeight = height[x][y];
    var imaSink = true;
    var bestDownhillHeight = myHeight;
    var bestDownhillX = x;
    var bestDownhillY = y;

    /*
        Visit the neighbors. If this cell is the lowest, then it's the
    sink. If not, find the steepest downhill direction.

        This would be the place to test the assumption that "If a cell
    is not a sink, you may assume it has a unique lowest neighbor and
    that this neighbor will be lower than the cell." But right now, we'll
    take that on faith.
    */
    function visit(deltaX,deltaY) {
        var neighborX = x+deltaX;
        var neighborY = y+deltaY;
        if (myHeight > height[neighborX][neighborY]) {
            imaSink = false;
            if (bestDownhillHeight > height[neighborX][neighborY]) {
                bestDownhillHeight = height[neighborX][neighborY];
                bestDownhillX = neighborX;
                bestDownhillY = neighborY;
            }
        }
    }
    if (x !== 0) {
        // upwards neighbor exists
        visit(-1,0);
    }
    if (x !== maxIndex) {
        // downwards neighbor exists
    visit(1,0);
    }
    if (y !== 0) {
        // left-hand neighbor exists
        visit(0,-1);
    }
    if (y !== maxIndex) {
        // right-hand neighbor exists
        visit(0,1);
    }

    downhillX[x][y] = bestDownhillX;
    downhillY[x][y] = bestDownhillY;
    return imaSink;
}

function exploreBasin(x,y,currentSize) {//,basinName) {
    //  This cell is in the basin.
    //basin[x][y] = basinName;
    currentSize++;

    /*
        Visit all neighbors that have this cell as the best downhill
    path and add them to the basin.
    */
    function visit(x,deltaX,y,deltaY) {
        if ((downhillX[x+deltaX][y+deltaY] === x) && (downhillY[x+deltaX][y+deltaY] === y)) {
            currentSize = exploreBasin(x+deltaX,y+deltaY,currentSize); //,basinName);
        }
        return 0;
    }
    if (x !== 0) {
        // upwards neighbor exists
        visit(x,-1,y,0);
    }
    if (x !== maxIndex) {
        // downwards neighbor exists
        visit(x,1,y,0);
    }
    if (y !== 0) {
        // left-hand neighbor exists
        visit(x,0,y,-1);
    }
    if (y !== maxIndex) {
        // right-hand neighbor exists
        visit(x,0,y,1);
    }

    return currentSize;
}

//  Read map from file (1st argument).
var lines = $EXEC('cat "' + $ARG[0] + '"').split('\n');
maxIndex = lines.shift() - 1;
for (var i = 0; i<=maxIndex; i++) {
    height[i] = lines.shift().split(' ');
    //  Create all other 2D arrays.
    sink[i] = [];
    downhillX[i] = [];
    downhillY[i] = [];
    //basin[i] = [];
}

//  Everyone decides if they are a sink. Create list of sinks (i.e. roots).
for (var x=0; x<=maxIndex; x++) {
    for (var y=0; y<=maxIndex; y++) {
        if (sink[x][y] = isSink(x,y)) {
            //  This node is a root (AKA sink).
            basinList.push([x,y]);
        }
    }
}
//for (var i = 0; i<=maxIndex; i++) { print(sink[i]); }

//  Each root explores it's basin.
//var basinName = 'A';
for (var i=basinList.length-1; i>=0; --i) { // i-- makes Closure Compiler sad
    var x = basinList[i][0];
    var y = basinList[i][1];
    basinSize.push(exploreBasin(x,y,0)); //,basinName));
    //basinName = String.fromCharCode(basinName.charCodeAt() + 1);
}
//for (var i = 0; i<=maxIndex; i++) { print(basin[i]); }

//  Done.
print(basinSize.sort(function(a, b){return b-a}).join(' '));

요소 객체를 별도의 배열로 나누고 가능한 모든 곳을 세계화하고 부작용을 수용함으로써 더 나은 최소화 결과를 얻었습니다. NSFW.

코드 최소화의 효과 :

  • 4537 바이트, 축소되지 않음
  • 1180 바이트, 패커
  • 855 바이트, 패커 + 손 최적화 (1 글자 글로벌 이름)
  • ADVANCED_OPTIMIZATIONS가 포함 된 751 바이트, Google 폐쇄 컴파일러
  • 730 바이트, 무모한 손 최적화 (나는 축소되지 않은 소스를 변경하지 않으므로 NSFW)
  • 707 바이트, 더 무모한 손 최적화 (싱크 []에 대한 모든 참조 제거);
  • 673 바이트, 모든 "var"제거, Nashorn -strict 플래그 삭제

원래 소스를 기꺼이 수정하려는 경우 최소화 된 코드를 편집하지 않고도 700 바이트에 근접 할 수있었습니다. 그러나 나는 그것을 그대로 두는 것이 출발점에서 흥미로운 견해를 제공한다고 생각하기 때문에하지 않았습니다.


을 (를) 단축 var e=[],g=[],h=[],l,m=[],q=[]할 수 있습니다 e=g=h=l=m=q=[]. var전역 변수를 숨기지 않으면 키워드 의 다른 용도도 제거 할 수 있습니다 .
nyuszika7h

할 수 없습니다. e = g = h = l = m = q = []는 모두 같은 배열에 대한 포인터를 사용합니다. 그리고 Nashorn은 var를 요구합니다.
Scott Leadley

@ nyuszika7h 당신은 내 틀에 박힌 내 쫓겨났다. Nashorn -strict를 삭제하고 모든 "var"을 삭제했습니다.
Scott Leadley

1

파이썬 : 276 306 365 바이트

이것은 나의 첫 번째 골프 시도입니다. 제안을 부탁드립니다!

편집 : 파일을 가져오고 닫는 데 너무 많은 문자가 걸립니다! 변수와 중첩 목록 이해에 파일을 저장하는 것도 마찬가지입니다.

t=map(int,open('a').read().split());n=t.pop(0);q=n*n;r,b,u=range(q),[1]*q,1
while u!=0:
    u=0
    for j in r:
        d=min((t[x],x)for x in [j,j-1,j+1,j-n,j+n]if int(abs(j/n-x/n))+abs(j%n-x%n)<=1 and x in r)[1]
        if j-d:u|=b[j];b[d]+=b[j];b[j]=0
for x in sorted(b)[::-1]:print x or '',

완전히 주석 처리됨 (2130 바이트 ...)

from math import floor
with open('a') as f:
    l = f.read()
    terrain = map(int,l.split()) # read in all the numbers into an array (treating the 2D array as flattened 1D)
    n = terrain.pop(0) # pop the first value: the size of the input
    valid_indices = range(n*n) # 0..(n*n)-1 are the valid indices of this grid
    water=[1]*(n*n) # start with 1 unit of water at each grid space. it will trickle down and sum in the basins.
    updates=1 # keep track of whether each iteration included an update

    # helper functions
    def dist(i,j):
        # returns the manhattan (L1) distance between two indices
        row_dist = abs(floor(j/n) - floor(i/n))
        col_dist = abs(j % n - i % n)
        return row_dist + col_dist

    def neighbors(j):
        # returns j plus up to 4 valid neighbor indices
        possible = [j,j-1,j+1,j-n,j+n]
        # validity criteria: neighbor must be in valid_indices, and it must be one space away from j
        return [x for x in possible if dist(x,j)<=1 and x in valid_indices]

    def down(j):
        # returns j iff j is a sink, otherwise the minimum neighbor of j
        # (works by constructing tuples of (value, index) which are min'd
        # by their value, then the [1] at the end returns its index)
        return min((terrain[i],i) for i in neighbors(j))[1]

    while updates!=0: # break when there are no further updates
        updates=0 # reset the update count for this iteration
        for j in valid_indices: # for each grid space, shift its water 
            d =down(j)
            if j!=d: # only do flow if j is not a sink
                updates += water[j] # count update (water[j] is zero for all non-sinks when the sinks are full!)
                water[d] += water[j] # move all of j's water into the next lowest spot
                water[j] = 0 # indicate that all water has flown out of j
    # at this point, `water` is zeros everywhere but the sinks.
    # the sinks have a value equal to the size of their watershed.
    # so, sorting `water` and printing nonzero answers gives us the result we want!
    water = sorted(water)[::-1] # [::-1] reverses the array (high to low)
    nonzero_water = [w for w in water if w] # 0 evaulates to false.
    print " ".join([str(w) for w in nonzero_water]) # format as a space-separated list

1 년 동안 골프를 치지 마십시오. 365자가 너무 좋습니다. : P
tomsmeding

1
나는 그것을 306으로 줄였습니다! 여분의 59 일의 휴가 시간이 필요합니다.
wrongu

당신은 할 수 있어야 open('a').read()한다고 생각합니다.
MrLemon

1

JavaScript (ECMAScript 6)-226 자

s=S.split(/\s/);n=s.shift(k=[]);u=k.a;t=s.map((v,i)=>[v,i,1]);t.slice().sort(X=(a,b)=>a[0]-b[0]).reverse().map(v=>{i=v[1];p=[v,i%n?t[i-1]:u,t[i-n],(i+1)%n?t[i+1]:u,t[+n+i]].sort(X)[0];p==v?k.push(v[2]):p[2]+=v[2]});k.join(' ')

설명

s=S.split(/\s/);                  // split S into an array using whitespace as the boundary.
n=s.shift();                      // remove the grid size from s and put it into n.
k=[];                             // an empty array to hold the position of the sinks.
u=k.a;                            // An undefined variable
t=s.map((v,i)=>[v,i,1]);          // map s to an array of:
                                  // - the elevation
                                  // - the position of this grid square
                                  // - the number of grid squares which have flowed into
                                  //      this grid square (initially 1).
X=(a,b)=>a[0]-b[0];               // A comparator function for sorting.
t.slice()                         // Take a copy of t
 .sort(X)                         // Then sort it by ascending elevation
 .reverse()                       // Reverse it to be sorted in descending order
 .map(v=>{                        // For each grid square (starting with highest elevation)
   i=v[1];                        // Get the position within the grid
   p=[v,i%n?t[i-1]:u,t[i-n],(i+1)%n?t[i+1]:u,t[+n+i]]
                                  // Create an array of the grid square and 4 adjacent
                                  //   squares (or undefined if off the edge of the grid)
     .sort(X)                     // Then sort by ascending elevation
     [0];                         // Then get the square with the lowest elevation.
   p==v                           // If the current grid square has the lowest elevation
     ?k.push(v[2])                // Then add the number of grid square which have
                                  //   flowed into it to k
     :p[2]+=v[2]});               // Else flow the current grid square into its lowest
                                  //   neighbour.
k.join(' ')                       // Output the sizes of the block with  space separation.

이전 버전-286 자

s=S.split(/\s/);n=s.shift()*1;k=[];u=k[1];t=s.map((v,i)=>({v:v,p:i,o:[]}));for(i in t){t[p=[t[i],i%n?t[i-1]:u,t[i-n],(+i+1)%n?t[+i+1]:u,t[+i+n]].sort((a,b)=>(a.v-b.v))[0].p].o.push([i]);p==i&&k.push([i])}k.map(x=>{while(x[L="length"]<(x=[].concat(...x.map(y=>t[y].o)))[L]);return x[L]})

입력이 변수에 있다고 가정합니다 S.

설명

s=S.split(/\s/);                  // split S into an array using whitespace as the boundary.
n=s.shift()*1;                    // remove the grid size from s and put it into n.
k=[];                             // an empty array to hold the position of the sinks.
u=k[1];                           // Undefined
t=s.map((v,i)=>({v:v,p:i,o:[]})); // map s to an Object with attributes:
                                  // - v: the elevation
                                  // - p: the position of this grid square
                                  // - o: an array of positions of neighbours which
                                  //      flow into this grid square.
for(i in t){                      // for each grid square
  p=[t[i],i%n?t[i-1]:u,t[i-n],(+i+1)%n?t[+i+1]:u,t[+i+n]]
                                  // start with an array containing the objects 
                                  //   representing that grid square and its 4 neighbours
                                  //   (or undefined for those neighbours which are
                                  //   outside the grid)
      .sort((a,b)=>(a.v-b.v))     // then sort that array in ascending order of elevation
      [0].p                       // then get the first array element (with lowest
                                  //   elevation) and get the position of that grid square.
  t[p].o.push([i]);               // Add the position of the current grid square to the
                                  //   array of neighbours which flow into the grid square
                                  //   we've just found.
  p==i&&k.push([i])               // Finally, if the two positions are identical then
                                  //   we've found a sink so add it to the array of sinks (k)
}
k.map(x=>{                        // For each sink start with an array, x, containing the
                                  //   position of the sink.
  while(x.length<(x=[].concat(...x.map(y=>t[y].o))).length);
                                  // Compare x to the concatenation of x with all the
                                  //   positions of grid squares which flow into squares
                                  //   in x and loop until it stops growing.
  return x.length                 // Then return the number of grid squares.
})

테스트

S="3\n1 5 2\n2 4 7\n3 6 9";
s=S.split(/\s/);n=s.shift()*1;k=[];u=k[1];t=s.map((v,i)=>({v:v,p:i,o:[]}));for(i in t){t[p=[t[i],i%n?t[i-1]:u,t[i-n],(+i+1)%n?t[+i+1]:u,t[+i+n]].sort((a,b)=>(a.v-b.v))[0].p].o.push([i]);p==i&&k.push([i])}k.map(x=>{while(x[L="length"]<(x=[].concat(...x.map(y=>t[y].o)))[L]);return x[L]})

출력 : [7, 2]

S="5\n1 0 2 5 8\n2 3 4 7 9\n3 5 7 8 9\n1 2 5 4 2\n3 3 5 2 1"
s=S.split(/\s/);n=s.shift()*1;k=[];u=k[1];t=s.map((v,i)=>({v:v,p:i,o:[]}));for(i in t){t[p=[t[i],i%n?t[i-1]:u,t[i-n],(+i+1)%n?t[+i+1]:u,t[+i+n]].sort((a,b)=>(a.v-b.v))[0].p].o.push([i]);p==i&&k.push([i])}k.map(x=>{while(x[L="length"]<(x=[].concat(...x.map(y=>t[y].o)))[L]);return x[L]})

출력 : [11, 7, 7]

S="4\n0 2 1 3\n2 1 0 4\n3 3 3 3\n5 5 2 1"
s=S.split(/\s/);n=s.shift()*1;k=[];u=k[1];t=s.map((v,i)=>({v:v,p:i,o:[]}));for(i in t){t[p=[t[i],i%n?t[i-1]:u,t[i-n],(+i+1)%n?t[+i+1]:u,t[+i+n]].sort((a,b)=>(a.v-b.v))[0].p].o.push([i]);p==i&&k.push([i])}k.map(x=>{while(x[L="length"]<(x=[].concat(...x.map(y=>t[y].o)))[L]);return x[L]})

출력 : [5, 7, 4]


1
내 눈에 화살표 (=>) 함수 정의가 훨씬 더 명확합니다.
Scott Leadley

1

줄리아, 315

function f(a,i,j)
    z=size(a,1)
    n=filter((x)->0<x[1]<=z&&0<x[2]<=z,[(i+1,j),(i-1,j),(i,j-1),(i,j+1)])
    v=[a[b...] for b in n]
    all(v.>a[i,j]) && (return i,j)
    f(a,n[indmin(v)]...)
end
p(a)=prod(["$n " for n=(b=[f(a,i,j) for i=1:size(a,1),j=1:size(a,2)];sort([sum(b.==s) for s=unique(b)],rev=true))])

현재 셀이 싱크인지 확인하거나 드레인을 찾은 모든 재귀 함수는 모든 인덱스 세트에서 호출합니다. 어쨌든 내가 이길 수 없기 때문에 입력 부분을 귀찮게하지 않았으며 그 부분은 재미 있지 않습니다.


1

하스켈, 271286

import Data.List
m=map
q[i,j]=[-1..1]>>= \d->[[i+d,j],[i,j+d]]
x%z=m(\i->snd.fst.minimum.filter((`elem`q i).snd)$zip(zip z[0..])x)x
g(n:z)=iterate(\v->m(v!!)v)(sequence[[1..n],[1..n]]%z)!!(n*n)
main=interact$unwords.m show.reverse.sort.m length.group.sort.g.m read.words

여전히 골프를 치는 코드 일 수도 있습니다.

& runhaskell 19188-Partition.hs <<INPUT
> 5
> 1 0 2 5 8
> 2 3 4 7 9
> 3 5 7 8 9
> 1 2 5 4 2
> 3 3 5 2 1
INPUT
11 7 7

설명

기본 아이디어 : 각 셀 (i, j) 에 대해 "이웃"에서 가장 낮은 셀을 찾으십시오. 그래프 [ (i, j)(mi, mj) ]가 나타납니다. 셀이 가장 낮은 셀인 경우 (i, j) == (mi, mj) 입니다.

이 그래프는 반복 될 수 있습니다. 그래프의 각 a → b 마다 a → c 로 대체하십시오. 여기서 b → c 의 그래프이다. 이 반복이 더 이상 변경되지 않으면 그래프의 각 셀은 플로우 할 가장 낮은 셀을 가리 킵니다.

이를 골프화하기 위해 몇 가지 변경 사항이 적용되었습니다. 첫째, 좌표는 쌍이 아닌 길이 2의 목록으로 표시됩니다. 둘째, 이웃이 발견되면, 셀은 2D 좌표가 아닌 셀의 선형 배열로 인덱스로 표시됩니다. 셋째, n * n 셀이 있으므로 n * n 반복 후에 그래프가 안정적이어야합니다.

언 골프

type Altitude = Int     -- altitude of a cell

type Coord = Int        -- single axis coordinate: 1..n
type Coords = [Coord]   -- 2D location, a pair of Coord
    -- (Int,Int) would be much more natural, but Coords are syntehsized
    -- later using sequence, which produces lists

type Index = Int        -- cell index
type Graph = [Index]    -- for each cell, the index of a lower cell it flows to


neighborhood :: Coords -> [Coords]                              -- golf'd as q
neighborhood [i,j] = concatMap (\d -> [[i+d,j], [i,j+d]]) [-1..1]
    -- computes [i-1,j] [i,j-1] [i,j] [i+1,j] [i,j+1]
    -- [i,j] is returned twice, but that won't matter for our purposes

flowsTo :: [Coords] -> [Altitude] -> Graph                      -- golf'd as (%)
flowsTo cs vs = map lowIndex cs
  where
    lowIndex is = snd . fst                          -- take just the Index of
                  . minimum                          -- the lowest of
                  . filter (inNeighborhood is . snd) -- those with coords nearby
                  $ gv                               -- from the data

    inNeighborhood :: Coords -> Coords -> Bool
    inNeighborhood is ds = ds `elem` neighborhood is

    gv :: [((Altitude, Index), Coords)]
        -- the altitudes paired with their index and coordinates
    gv = zip (zip vs [0..]) cs


flowInput :: [Int] -> Graph                                     -- golf'd as g
flowInput (size:vs) = iterate step (flowsTo coords vs) !! (size * size)
  where
    coords = sequence [[1..size],[1..size]]
        -- generates [1,1], [1,2] ... [size,size]

    step :: Graph -> Graph
    step v = map (v!!) v
        -- follow each arc one step

main' :: IO ()
main' = interact $
            unwords . map show      -- counts a single line of text
            . reverse . sort        -- counts from hi to lo
            . map length            -- for each common group, get the count
            . group . sort          -- order cells by common final cell index
            . flowInput             -- compute the final cell index graph
            . map read . words      -- all input as a list of Int

여기서 무슨 일이 일어나고 있는지 설명 할 수 있다면 좋을 것입니다.
찰스

@ 찰스-완료!
MtnViewMark

1

루비, 216

r=[]
M=gets('').split.map &:to_i
N=M.shift
g=M.map{1}
M.sort.reverse.map{|w|t=[c=M.index(w),c%N<0?c:c-1,c%N<N-1?c+1:c,c+N,c-N].min_by{|y|M[y]&&y>=0?M[y]:M.max}
M[c]+=1
t!=c ?g[t]+=g[c]:r<<g[c]}
$><<r.sort.reverse*' '

약간 다른 접근 방식으로 각 사각형에서 한 번만 "흐름"을 호출합니다 (성능은 Array :: index의 성능에 따라 다릅니다). 가장 높은 고도에서 가장 낮은 고도로 이동하여 한 번에 하나의 셀을 가장 낮은 이웃으로 비우고 완료되면 셀을 (높이에 1을 추가하여) 표시합니다.

주석 처리 및 간격 :

results=[]
ELEVATIONS = gets('').split.map &:to_i  # ELEVATIONS is the input map
MAP_SIZE = ELEVATIONS.shift             # MAP_SIZE is the first line of input
watershed_size = ELEVATIONS.map{1}      # watershed_size is the size of the watershed of each cell

ELEVATIONS.sort.reverse.map { |water_level| 
    # target_index is where the water flows to.  It's the minimum elevation of the (up to) 5 cells:
    target_index = [
        current_index = ELEVATIONS.index(water_level),                              # this cell
        (current_index % MAP_SIZE) < 0           ? current_index : current_index-1, # left if possible
        (current_index % MAP_SIZE) >= MAP_SIZE-1 ? current_index : current_index+1, # right if possible
        current_index + MAP_SIZE,                                                   # below
        current_index - MAP_SIZE                                                    # above
    ].min_by{ |y|
        # if y is out of range, use max. Else, use ELEVATIONS[y]
        (ELEVATIONS[y] && y>=0) ? ELEVATIONS[y] : ELEVATIONS.max
    }
# done with this cell.
# increment the elevation to mark done since it no longer matters
ELEVATIONS[current_index] += 1

# if this is not a sink
(target_index != current_index) ? 
    # add my watershed size to the target's
    watershed_size[target_index] += watershed_size[current_index] 
    # else, push my watershed size onto results
    : results << watershed_size[current_index]}

변경 로그:

216-범위를 벗어난 지수를 선택 해제하는 더 좋은 방법

221- "2"가 "2"앞에옵니다 ...로 되돌아 가지만 to_i공간을 절약하십시오.gets 가지만 es의 .

224-왜 선언 s할까? 그리고 each=>map

229-대규모 골프-고도를 먼저 정렬 swhile 절 을 삭제하고 min_by대신에 사용 하고 고도에 sort_by{...}[0]신경 쓰지 말고 to_i사용 flat_map및 축소하십시오.select{} 블록을

271-유역 크기를 새 배열로 이동하고 sort_by 사용

315-결과를 배열로 이동하여 모든 종류의 이점을 제공하고 인접 인덱스 목록을 단축했습니다. 인덱스 람다에서 하나의 문자를 얻었습니다.

355-첫 커밋


1

파이썬- -470 4445445939392 378 3763753774 369 바이트

나는 멈출 수 없다!

이기는 솔루션은 아니지만 많은 재미가있었습니다. 이 버전은 입력이 어디에나 저장되는 것으로 가정하지 않고 대신 stdin에서 읽습니다. 최대 재귀 깊이 = 점에서 싱크까지의 가장 긴 거리.

def f(x,m=[],d=[],s=[]):
 n=[e[a]if b else 99for a,b in(x-1,x%z),(x+1,x%z<z-1),(x-z,x/z),(x+z,x/z<z-1)];t=min(n)
 if t<e[x]:r=f(x+(-1,1,-z,z)[n.index(t)])[0];s[r]+=x not in m;m+=[x]
 else:c=x not in d;d+=[x]*c;r=d.index(x);s+=[1]*c
 return r,s
z,e=input(),[]
exec'e+=map(int,raw_input().split());'*z
for x in range(z*z):s=f(x)[1]
print' '.join(map(str,sorted(s)[::-1]))

오늘 설명 할 시간이 없지만 다음은 코드가없는 코드입니다.

실제로 원래 코드와는 상당히 다릅니다. 나는 stdin에서 S 행을 읽고, 분할하고, 정수로 매핑하고 목록을 평탄화하여 평평한 필드를 얻습니다. 그런 다음 모든 타일을 반복합니다 (타일이라고 부릅니다). flow-function은 인접한 타일을 확인하고 가장 작은 값을 가진 타일을 선택합니다. 현재 타일의 값보다 작은 경우 이동하여 재귀하십시오. 그렇지 않은 경우, 현재 타일은 싱크대이며 새로운 분지가 생성됩니다. 재귀의 반환 값은 유역의 id입니다.

# --- ORIGINAL SOURCE ---

# lowest neighboring cell = unique and next
# neihboring cells all higher = sink and end

basinm = [] # list of the used tiles
basins = {} # list of basin sizes
basinf = [] # tuples of basin sinks
field = []  # 2d-list representing the elevation map
size = 0

def flow(x, y):
    global basinf, basinm
    print "Coordinate: ", x, y
    nearby = []
    nearby += [field[y][x-1] if x > 0 else 99]
    nearby += [field[y][x+1] if x < size-1 else 99]
    nearby += [field[y-1][x] if y > 0 else 99]
    nearby += [field[y+1][x] if y < size-1 else 99]
    print nearby
    next = min(nearby)
    if next < field[y][x]:
        i = nearby.index(next)
        r = flow(x+(-1,1,0,0)[i], y+(0,0,-1,1)[i])
        if (x,y) not in basinm:
            basins[r] += 1
            basinm += [(x,y)]
    else:
        c = (x,y) not in basinf
        if c:
            basinf += [(x,y)]
        r = basinf.index((x,y))
        if c: basins[r] = 1
    return r

size = input()
field = [map(int,raw_input().split()) for _ in range(size)]
print field
for y in range(size):
    for x in range(size):
        flow(x, y)
print
print ' '.join(map(str,sorted(basins.values(),reverse=1)))

1

자바 스크립트 (ES6) 190 203

편집하다좀 더 ES6ish (1 년 후 ...)

줄 바꿈을 포함하여 입력 행이 문자열로 포함 된 함수를 정의하고 후행 공백이있는 문자열로 출력을 리턴합니다.

F=l=>{[s,...m]=l.split(/\s+/);for(j=t=[];k=j<s*s;t[i]=-~t[i])for(i=j++;k;i+=k)k=r=0,[for(z of[-s,+s,i%s?-1:+s,(i+1)%s?1:+s])(q=m[z+i]-m[i])<r&&(k=z,r=q)];return t.sort((a,b)=>b-a).join(' ')}

// Less golfed
U=l=>{
      [s,...m] = l.split(/\s+/);
      for (j=t=[]; k=j<s*s; t[i]=-~t[i])
        for(i=j++; k; i+=k)
          k=r=0,
          [for(z of [-s,+s,i%s?-1:+s,(i+1)%s?1:+s]) (q=m[z+i]-m[i]) < r && (k=z,r=q)];
      return t.sort((a,b)=>b-a).join(' ')
    }

// TEST    
out=x=>O.innerHTML += x + '\n';

out(F('5\n1 0 2 5 8\n 2 3 4 7 9\n 3 5 7 8 9\n 1 2 5 4 2\n 3 3 5 2 1'))// "11 7 7"

out(F('4\n0 2 1 3\n2 1 0 4\n3 3 3 3\n5 5 2 1')) //"7 5 4"
<pre id=O></pre>


0

펄 6, 419 404

명확성을 위해 줄 바꿈이 추가되었습니다. 안전하게 제거 할 수 있습니다.

my \d=$*IN.lines[0];my @a=$*IN.lines.map(*.trim.split(" "));my @b;my $i=0;my $j=0;
for @a {for @$_ {my $c=$_;my $p=$i;my $q=$j;my &y={@a[$p+$_[0]][$q+$_[1]]//Inf};
loop {my @n=(0,1),(1,0);push @n,(-1,0) if $p;push @n,(0,-1) if $q;my \o=@n.sort(
&y)[0];my \h=y(o);last if h>$c;$c=h;$p+=o[0];$q+=o[1]};@b[$i][$j]=($p,$q);++$j};
$j=0;++$i};say join " ",bag(@b.map(*.flat).flat.map(~*)).values.sort: {$^b <=>$^a}

오래된 해결책 :

my \d=$*IN.lines[0];my @a=$*IN.lines.map(*.trim.split(" "));my @b;my $i=0;my $j=0;
for @a {for @$_ {
my $c=$_;my $p=$i;my $q=$j;
loop {my @n=(0,1),(1,0);@n.push: (-1,0) if $p;@n.push: (0,-1) if $q;
my \o=@n.sort({@a[$p+$_[0]][$q+$_[1]]//Inf})[0];
my \h=@a[$p+o[0]][$q+o[1]];last if h>$c;
$c=h;$p+=o[0];$q+=o[1]};@b[$i][$j]=($p,$q);++$j};$j=0;++$i};
say join " ",bag(@b.map(*.flat.flat).flat.map(~*)).values.sort: {$^b <=>$^a}

그러나 파이썬과 JavaScript 솔루션에 구타를 당합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.