Su akışlarının haritasını bölümleme


17

Bu, internette Palantir Technologies tarafından röportajlarında sorulan bir zorluk .

Bir grup çiftçinin bazı yükseklik verileri vardır ve yağmurun tarım arazileri boyunca nasıl aktığını anlamalarına yardımcı olacağız. Toprağı iki boyutlu bir yükseklik dizisi olarak temsil edeceğiz ve suyun yokuş aşağı aktığı fikrine dayanarak aşağıdaki modeli kullanacağız:

Bir hücrenin dört komşu hücresinin daha yüksek rakımları varsa, bu hücreye bir lavabo diyoruz; su lavabolarda toplanır. Aksi takdirde, su en düşük irtifada olan komşu hücreye akacaktır. Hücre bir lavabo değilse, benzersiz bir en düşük komşusuna sahip olduğunu ve bu komşunun hücreden daha düşük olacağını varsayabilirsiniz.

Doğrudan veya dolaylı olarak aynı lavaboya akan hücrelerin aynı havzanın bir parçası olduğu söylenir.

Zorluklarınız haritayı havzalara bölmektir. Özellikle, bir yükseklik haritası verildiğinde, kodunuz haritayı havzalara ayırmalı ve havzaların boyutlarını azalan sırada vermelidir.

Yükseklik haritalarının kare olduğunu varsayalım. Giriş, haritanın bir tamsayı, S, yüksekliği (ve genişliği) olan bir çizgiyle başlayacaktır. Sonraki S satırlarının her biri haritanın bir satırını içerecektir, her biri S tamsayıları olan - satırdaki S hücrelerinin yükseltileri. Bazı çiftçilerin aşağıdaki örnekler gibi küçük arsaları, bazılarında ise daha büyük arsaları vardır. Bununla birlikte, hiçbir durumda bir çiftçi S = 5000'den daha büyük bir arsaya sahip olmayacaktır.

Kodunuz, havza boyutlarının boşlukla ayrılmış bir listesini azalan sırada vermelidir. (Sondaki boşluklar yoksayılır.)

Aşağıda birkaç örnek verilmiştir.

Giriş:

3
1 5 2
2 4 7
3 6 9 

Çıktı: 7 2

A ve B ile işaretlenmiş havzalar şunlardır:

A A B
A A B
A A A 

Giriş:

1
10

Çıktı: 1

Bu durumda sadece bir lavabo var.

Giriş:

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 

Çıktı: 11 7 7

A, B ve C ile etiketlenmiş havzalar şunlardır:

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 

Giriş:

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

Çıktı: 7 5 4

A, B ve C ile etiketlenmiş havzalar şunlardır:

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

1
Sorunuzu bu site için daha uygun hale getirmek üzere düzenledim. Daha önce, bir programlama sorusu / kod incelemesiydi. Şimdi meydan okuma biçimindedir. Bu site, girişimleri için topluluğa kod zorlukları / sorunları bırakmak içindir. Not: hala kazanan bir kritere ihtiyacınız vardır: en kısa kod ( kod golf ) önerilir.
Justin

2
@ OP Orijinal sorunuz için bir dizi alternatif golfçü çözüm yerine bir cevap istiyorsanız, Stack Overflow'da (ya da belki Code Review?) Tekrar sormanızı öneririm
Gareth

1
@JanDvorak Bence düzenleme önce orijinal soru Kod İnceleme iyi olabilir (başlamak için herhangi bir golf yoktu)? Muhtemelen SO konusunda haklısın.
Gareth

1
@JanDvorak Ben sadece onu düzenlemek ve geçerli bir kod golf yapmak düşünüyorum
Justin

1
Sorunu kod incelemesinde yayınladım - codereview.stackexchange.com/questions/39895/…
AnkitSablok

Yanıtlar:


8

Mathematica

Havza ölçüsü listesi

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

mverilen giriş verileri nerede . Sorudaki gibi bir matrisi görüntülemek için, yerine bir // Reverse@Sort@Part[Tally[Flatten@#], All, 2] &tane /. {1 -> "A", 2 -> "B", 3 -> "C"} // MatrixFormya da kullanmak yerine bir görüntü olarak görüntülenebilir //ImageAdjust//Image.


Bizi asılı bırakma! Sıralanan lavabo boyutu listesinde BinCounts [] ve Sort [] kullanılır, değil mi?
Scott Leadley

@ScottLeadley İstenen havza boyutu listesi olduğunu fark etmedim, bunu işaret ettiğiniz için teşekkür ederim. Cevabı düzelttim (son bölüm muhtemelen çok daha kısa yapılabilir).

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(" "));

Test sonuçları (Nashorn kullanarak):

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

Muhtemelen 5000 büyüklüğündeki haritalar için yığın problemleri olacaktır (ancak bu bir uygulama detayıdır :).

Tüm bu felaketin içindeki en küçük kaynak:

// 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(' '));

Element nesnelerini ayrı dizilere ayırarak, mümkün olan her yerde küreselleşerek ve yan etkileri kucaklayarak daha iyi minimizasyon sonuçları elde ettim. NSFW.

Kod minimizasyonunun etkileri:

  • 4537 bayt, değiştirilmemiş
  • 1180 bayt, paketleyici
  • 855 bayt, packer + el optimizasyonları (1 karakter global adı)
  • 751 bayt, ADVANCED_OPTIMIZATIONS ile Google Closure Derleyici (NB, ölü kod olarak bir "dönüş 0" seçti)
  • 730 bayt, pervasız el optimizasyonu (En küçük kaynağı değiştirmiyorum, bu yüzden NSFW)
  • 707 bayt, daha pervasız el optimizasyonu (lavabo [] için tüm referansları kaldırın);
  • 673 bayt, tüm "var" s kaldırmak, Nashorn -strict bayrağı bırakın

Orijinal kaynağı değiştirmeye istekli olsaydım, küçültülmüş kodu düzenlemeden 700 bayta yakın bir başarı elde edebilirdim. Ama öyle olmadı, çünkü olduğu gibi bırakma başlangıç ​​noktasından ilginç bir görünüm veriyor.


Sen kısaltabilir var e=[],g=[],h=[],l,m=[],q=[]için e=g=h=l=m=q=[]. varHerhangi bir global değişkeni gölgelemiyorsanız , anahtar kelimenin diğer kullanımlarından da kurtulabilirsiniz .
nyuszika7h

@ nyuszika7h Yapamaz. e = g = h = l = m = q = [] aynı diziye bir işaretçi kullanarak hepsine sahip olur. Ve Nashorn var gerektirir.
Scott Leadley

@ nyuszika7h Sen benim rut'umdan kovuldun. Nashorn -strict'i düşürdüm ve tüm "var" ları sildim.
Scott Leadley

1

Python: 276 306 365 bayt

Bu benim ilk golf girişimim. Öneriler takdir edilmektedir!

edit: ithalat ve kapanış dosyaları çok fazla karakter alır! Değişkenlerde ve iç içe liste kavramada dosya depolamak da öyle.

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 '',

tamamen yorumlandı (2130 bayt ...)

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

Lütfen bir yıl golf oynama. 365 karakter çok güzel. : P
tomsmeding

1
306'ya indirdim! Ekstra 59 günlük tatil zamanına ihtiyacım var.
wrongu

Sadece yapabilmelisin open('a').read(), sanırım.
MrLemon

1

JavaScript (ECMAScript 6) - 226 Karakter

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(' ')

açıklama

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.

Önceki Sürüm - 286 Karakter

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]})

Girdinin bir değişken içinde olduğunu varsayar S;

açıklama

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.
})

Ölçek

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]})

Çıktılar: [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]})

Çıktılar: [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]})

Çıktılar: [5, 7, 4]


1
Benim için ok (=>) fonksiyon tanımları çok daha net.
Scott Leadley

1

Julia, 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))])

Geçerli hücrenin bir lavabo olduğunu belirleyen veya tahliyeyi bulan özyinelemeli bir işlev, daha sonra bunu her dizin dizisinde çağırır. Ben zaten kazanmak için değildi ve bu kısmı eğlenceli değil çünkü giriş kısmı yapmak için uğraşmadı.


1

Haskell, 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

Burada golf için hala bir kod olabilir.

& 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

açıklama

Temel fikir: Her hücre için (i, j) "mahallede" en düşük hücreyi bulun. Bu bir grafik verir [ (i, j)(mi, mj) ]. Bir hücre en düşük hücrenin kendisiyse, (i, j) == (mi, mj) .

Bu grafik, yinelenebilen: her biri için A → B grafikte, ile değiştirin bir → c burada b → c grafikte . Bu yineleme daha fazla değişiklik vermediğinde, grafikteki her hücre akacağı en düşük hücreyi gösterir.

Bunu golf oynamak için çeşitli değişiklikler yapıldı: İlk olarak, koordinatlar bir çift değil, 2 uzunluk listesi olarak temsil edilir. İkincisi, komşular bulunduğunda, hücreler indeksleriyle 2B koordinatları değil, doğrusal bir hücre dizisi olarak temsil edilir. Üçüncüsü, n * n hücreleri olduğu için, n * n yinelemelerinden sonra grafik kararlı olmalıdır.

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

Burada neler olduğunu açıklayabilirseniz harika olur.
Charles

@Charles - bitti!
MtnViewMark

1

Ruby, 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*' '

Biraz farklı bir yaklaşım, her karede yalnızca bir kez "akış" çağrılıyor (performans Array :: index'in performansına bağlıdır). En yüksek rakımdan en alçak seviyeye gider, her seferinde bir hücreyi en düşük komşusuna boşaltır ve bittiğinde yapılan hücreyi işaretler (yükselmeye 1 ekleyerek).

Yorum ve aralıklı:

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

Değişiklikler:

216 - Sınırların dışındaki endekslerin seçimini kaldırmanın daha iyi yolu

221 - çıkıyor, "11" "2" den önce geliyor ... geri dön to_i, ama bizim yer biraz tasarrufgets es .

224 - Neden ilan settiniz? Veeach =>map

229 - masif golf - kotları önce sıralayın s(ve böylelikle whilehükmü bırakın ), min_byyerine kullanın , sort_by{...}[0]kotlar to_iiçin rahatsız etmeyin , kullanın flat_mapve küçültün select{}blok

271 - Havza boyutunu yeni diziye taşıdı ve sort_by kullandı

315 - sonuçları her türlü fayda sağlayan diziye taşıdı ve komşu dizin listesini kısalttı. Ayrıca endeks lambda bir karakter kazandı.

355 - ilk taahhüt


1

Python - 47044744453933923783763735374 369 bayt

Kendimi durduramıyorum!

Kazanan bir çözüm değil, ama bunu yaparken çok eğlendim. Bu sürüm, girdinin hiçbir yerde saklanacağını varsaymaz ve bunun yerine stdin'den okur. Maksimum özyineleme derinliği = bir noktadan lavaboya en uzun mesafe.

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

Bugün açıklamak için zamanım yok, ama işsiz kod:

Aslında orijinal koddan oldukça farklı. Stdin'den S satırlarını okudum, ayırdım, ints'a eşledim ve düzleştirilmiş alanı elde etmek için listeleri düzleştirdim. Sonra bir kez tüm fayans döngü (onlara fayans diyelim). Akış fonksiyonu komşu döşemeleri kontrol eder ve en küçük değere sahip olanı seçer. Geçerli döşemenin değerinden daha küçükse, ona taşıyın ve tekrarlayın. Değilse, geçerli karo bir lavabodur ve yeni havza oluşturulur. Özyinelemenin dönüş değeri havzanın kimliği.

# --- 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

Düzenle Biraz daha ES6ish (1 yıl sonra ...)

Yeni satırlar da dahil olmak üzere giriş satırları olan bir işlevi tanımlayın, çıkışı boşlukları olan dize olarak döndürün

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

Netlik için yeni satırlar eklendi. Bunları güvenle kaldırabilirsiniz.

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}

Eski çözüm:

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}

Yine de Python ve JavaScript çözümleri tarafından dövülüyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.