แบ่งแผนที่น้ำไหล


17

นี่คือความท้าทายบนอินเทอร์เน็ตที่ถามโดย Palantir เทคโนโลยีในการสัมภาษณ์ของพวกเขา

กลุ่มเกษตรกรมีข้อมูลระดับความสูงและเราจะช่วยให้พวกเขาเข้าใจว่าปริมาณน้ำฝนไหลผ่านพื้นที่การเกษตรของพวกเขาอย่างไร เราจะเป็นตัวแทนของดินแดนในระดับความสูงสองมิติและใช้แบบจำลองต่อไปนี้ตามแนวคิดที่ว่าน้ำไหลลงเขา:

หากเซลล์สี่เซลล์ที่อยู่ใกล้เคียงทั้งหมดมีระดับความสูงที่สูงกว่าเราเรียกเซลล์นี้ว่า sink น้ำเก็บในอ่างล้างจาน มิฉะนั้นน้ำจะไหลไปยังเซลล์ข้างเคียงซึ่งมีระดับความสูงต่ำสุด หากเซลล์ไม่ใช่อ่างล้างจานคุณอาจคิดว่ามีเพื่อนบ้านต่ำสุดที่ไม่เหมือนใครและเพื่อนบ้านนั้นจะต่ำกว่าเซลล์

เซลล์ที่ระบายลงในอ่างเดียวกันไม่ว่าโดยตรงหรือโดยอ้อมจะกล่าวว่าเป็นส่วนหนึ่งของอ่างเดียวกัน

ความท้าทายของคุณคือการแบ่งแผนที่เป็นแอ่ง โดยเฉพาะอย่างยิ่งเมื่อได้รับแผนที่ระดับความสูงรหัสของคุณควรแบ่งแผนที่เป็นแอ่งและส่งขนาดของแอ่งตามลำดับจากมากไปน้อย

สมมติว่าแผนที่ความสูงเป็นรูปสี่เหลี่ยมจัตุรัส อินพุตจะเริ่มต้นด้วยบรรทัดที่มีจำนวนเต็มหนึ่งตัวคือ 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's และ 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's และ C คือ:

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

1
ฉันแก้ไขคำถามของคุณเพื่อให้เหมาะสมกับไซต์นี้มากขึ้น ก่อนหน้านี้มันเป็นคำถามการเขียนโปรแกรม / ตรวจสอบรหัส ตอนนี้มันอยู่ในรูปของการท้าทาย ไซต์นี้มีไว้สำหรับปล่อยความท้าทาย / ปัญหาเกี่ยวกับรหัสให้กับชุมชนเพื่อให้พวกเขาลอง หมายเหตุ: คุณยังต้องการเกณฑ์การชนะ: แนะนำรหัสที่สั้นที่สุด ( รหัสกอล์ฟ )
Justin

2
@OP หากคุณต้องการคำตอบสำหรับคำถามเดิมของคุณแทนจำนวนของโซลูชั่นแข็งแรงเล่นกอล์ฟทางเลือกหนึ่งที่ผมขอแนะนำให้ขอให้มันอีกครั้งในกองมากเกิน (หรืออาจรหัสตรวจสอบ?)
แกเร็ ธ

1
@JanDvorak ฉันคิดว่าคำถามดั้งเดิมก่อนที่จะแก้ไขอาจไม่เป็นไรในการตรวจสอบโค้ด (ไม่มีการเล่นกอล์ฟที่เกี่ยวข้องเริ่มต้นด้วย) คุณอาจพูดถูกดังนั้น
Gareth

1
@JanDvorak ผมคิดว่าเพียงแค่แก้ไขมันออกมาและทำให้มันถูกต้องรหัสกอล์ฟ
จัสติน

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 [] & เรียง [] ใช่ไหม
Scott Leadley

@ScottLeadley ฉันไม่ทราบว่ามันเป็นรายการขนาดอ่างที่ร้องขอขอขอบคุณสำหรับการชี้ให้เห็นว่า ฉันได้แก้ไขคำตอบแล้ว (แม้ว่าส่วนสุดท้ายอาจสั้นลงได้มาก)

2

JavaScript - 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 ตัว)
  • 751 ไบต์, Google ปิดคอมไพเลอร์ที่มี ADVANCED_OPTIMIZATIONS (NB มันทำให้ร่องรอย "คืน 0" เป็นรหัสที่ตายแล้ว)
  • 730 bytes, การเพิ่มประสิทธิภาพด้วยมือโดยประมาท (ฉันไม่ได้เปลี่ยนแหล่งที่ไม่ได้ระบุดังนั้น NSFW)
  • 707 ไบต์, การเพิ่มประสิทธิภาพด้วยมือที่ประมาทมากขึ้น (ลบการอ้างอิงทั้งหมดเพื่อจม []);
  • 673 ไบต์ลบ "var" s ทั้งหมดปล่อยแฟล็ก Nashorn -strict

ฉันสามารถทำได้ใกล้ถึง 700 ไบต์โดยไม่ต้องแก้ไขรหัสย่อเล็กสุดถ้าฉันยินดีที่จะแก้ไขต้นฉบับ แต่ฉันไม่ได้เพราะฉันคิดว่าการปล่อยให้เป็น - จะให้มุมมองที่น่าสนใจจากจุดเริ่มต้น


คุณสามารถร่นไปvar e=[],g=[],h=[],l,m=[],q=[] e=g=h=l=m=q=[]คุณอาจกำจัดการใช้varคำหลักอื่น ๆ ได้เช่นกันหากคุณไม่ได้ทำเงาตัวแปรทั่วโลก
nyuszika7h

@ nyuszika7h ไม่สามารถทำได้ e = g = h = l = m = q = [] จะมีทั้งหมดโดยใช้ตัวชี้ไปยังอาร์เรย์เดียวกัน และ Nashorn ต้องการ var
Scott Leadley

@ nyuszika7h คุณเตะฉันออกจากร่องของฉัน ฉันทิ้ง Nashorn-strict และลบ "var" ทั้งหมด
Scott Leadley

1

Python: 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

โปรดอย่าตีกอล์ฟหนึ่งปี 365 ตัวอักษรดีเกินไป : P
tomsmeding

1
ฉันลงไปที่ 306! ฉันต้องการวันหยุดพักผ่อนเพิ่ม 59 วัน
misu

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

Haskell, 271 286

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)MJ)

กราฟนี้สามารถทำซ้ำได้: สำหรับแต่ละ→ bในกราฟให้แทนที่ด้วย→ c โดยที่ b → cอยู่ในกราฟ เมื่อการวนซ้ำนี้ไม่มีการเปลี่ยนแปลงอีกต่อไปแต่ละเซลล์ในกราฟจะชี้ไปที่เซลล์ต่ำสุดที่จะไหลไป

ในการเล่นกอล์ฟมีการเปลี่ยนแปลงหลายอย่าง: อันดับแรกพิกัดจะแสดงเป็นรายการความยาว 2 แทนที่จะเป็นคู่ ประการที่สองเมื่อพบเพื่อนบ้านแล้วเซลล์จะถูกแสดงด้วยดัชนีของพวกเขาลงในอาร์เรย์เชิงเส้นของเซลล์ไม่ใช่พิกัด 2D ประการที่สามเนื่องจากมีเซลล์ n * n หลังจากทำซ้ำ n * n กราฟจะต้องเสถียร

Ungolf'd

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

มันจะดีถ้าคุณสามารถอธิบายสิ่งที่เกิดขึ้นที่นี่
ไม่ใช่ว่า Charles

@Charles - เสร็จแล้ว!
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 ::) มันเริ่มจากระดับความสูงสูงสุดไปสู่ระดับต่ำสุดโดยปล่อยเซลล์หนึ่ง ๆ ออกไปทีละน้อยสู่เพื่อนบ้านที่ต่ำที่สุดและทำเครื่องหมายเซลล์ที่ทำเสร็จแล้ว (โดยเพิ่ม 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 - ปรากฎว่า "11" มาก่อน "2" ... ย้อนกลับไปto_iแต่กลับประหยัดพื้นที่บนเราgets es

224 - ทำไมต้องประกาศsด้วยล่ะ? และeach=>map

229 - การตีกอล์ฟครั้งใหญ่ - จัดเรียงระดับความสูงก่อนs(และลดระดับwhileประโยค) ใช้min_byแทนsort_by{...}[0]ไม่ต้องกังวลto_iกับระดับความสูงการใช้flat_mapและการหดตัวของselect{}บล็อก

271 - ย้ายขนาดลุ่มน้ำไปยังอาร์เรย์ใหม่และใช้ sort_by

315 - ย้ายผลลัพธ์ไปยังอาร์เรย์ซึ่งให้ประโยชน์ทุกประเภทและทำให้รายการดัชนีเพื่อนบ้านสั้นลง ยังได้รับหนึ่งอักขระในดัชนีแลมบ์ดา

355 - กระทำก่อน


1

Python - 470 447 445 393 392 378 376 375 374 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]))

ฉันไม่มีเวลาอธิบายวันนี้ แต่นี่เป็นโค้ดที่ไม่ดีนัก:

จริง ๆ แล้วมันค่อนข้างแตกต่างจากรหัสต้นฉบับ ฉันอ่านบรรทัด S จาก stdin, แยก, แผนที่ไปยัง ints และทำให้รายการเรียบเพื่อให้ได้ฟิลด์ที่แบน จากนั้นฉันวนลูปผ่านไทล์ทั้งหมด (ขอเรียกว่าไทล์ไพ่) หนึ่งครั้ง ฟังก์ชั่นการไหลจะตรวจสอบกระเบื้องที่อยู่ใกล้เคียงและเลือกอันที่มีค่าน้อยที่สุด หากมีขนาดเล็กกว่ามูลค่าของไทล์ปัจจุบันให้ย้ายไปที่รีเซ็ท ถ้าไม่กระเบื้องปัจจุบันเป็นอ่างและอ่างใหม่จะถูกสร้างขึ้น ค่าส่งคืนของการสอบถามซ้ำคือ 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

JavaScript (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

Perl 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}

แต่ถึงกระนั้นฉันก็พ่ายแพ้โดย Python และ JavaScript

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.