首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >下雨时倾盆大雨--2016年8月社区挑战

下雨时倾盆大雨--2016年8月社区挑战
EN

Code Review用户
提问于 2016-08-04 15:12:51
回答 3查看 478关注 0票数 24

1.导言

这段代码是我解决2016年年8月社区挑战的尝试。来自一个每天下着猫和狗的城市,这个挑战就在我的巷子里。

2.算法

我使用了200_成功♦他在这里的回答中概述的解决方案:

  1. 每个Cell都跟踪它属于哪个Basin;每个Cell最初假设在自己的Basin中。每个Basin都有一个sink,或最低的Cell,它充当Basin的“代表元素”,以及一个成员计数。Topography跟踪所有的Basins。
  2. 对于每一个Basin,查找最低的水槽的邻居。如果最低的不是这个Basin的成员,把它的细胞转移到最低的邻居的Basin,并通知Topography更高的盆地不再存在。
  3. 重复步骤2,直到不需要采取进一步的行动为止。
  4. Topography列举Basins及其计数。

3.输入和输出

示例1

输入:rainfall-example-1.txt

输出:

代码语言:javascript
复制
Height Farmland:
[[1 5 2]
 [2 4 7]
 [3 6 9]]

Basins:
 (A)  A  (B) 
  A   A   B  
  A   A   A  

Letter  Size  Sink
A       7     (0, 0) 
B       2     (0, 2) 

示例2

输入:rainfall-example-2.txt

输出:

代码语言:javascript
复制
Height Farmland:
[[1 0 2 5 8]
 [2 3 4 7 9]
 [3 5 7 8 9]
 [1 2 5 4 3]
 [3 3 5 2 1]]

Basins:
  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) 

Letter  Size  Sink
A       11    (0, 1) 
B        7    (3, 0) 
C        7    (4, 4) 

示例3

输入:rainfall-example-3.txt

输出:

代码语言:javascript
复制
Height Farmland:
[[0 2 1 3]
 [2 1 0 4]
 [3 3 3 3]
 [5 5 2 1]]

Basins:
 (B)  B   A    A  
  B   A  (A)   A  
  B   A   A    C  
  B   C   C   (C) 

Letter  Size  Sink
A       7     (1, 2) 
B       5     (0, 0) 
C       4     (3, 3) 

示例4

输入:rainfall-example-4.txt

输出:

代码语言:javascript
复制
Height Farmland:
[[ 4 23 25 21 29 16 23 29 12 28]
 [ 0 12 26  0 19 23  9 13 11 29]
 [26 24 18 21 22  4 29  1  5 28]
 [13 15 18  3  6  7 15 15  0  9]
 [29 29 23  6 28  1 11  1  3 21]
 [ 6  3  0 13 11  0 28  0 25 17]
 [20 15  7 24  3  8  5 21 12 23]
 [ 0  9 24 12 19 23  9 29 26 21]
 [ 1 12 12  2 14  2  0 16  2  6]
 [14  5 14  7 26 12 24  6  5 25]
 [18 25 20 29 17 23 23  2 24 19]
 [ 9  0  6  2 19 19 12 10 18 28]
 [ 8 27  7 23 14  9  3 14 18 25]
 [ 6 19 13  9  3  0 21  3  2 16]
 [ 6  1 14 12 19 22 15  2 19 12]
 [17 24 27  8 15 26 16  6  0 27]
 [ 0 15  3  4  2 19  0  3 17 19]
 [ 3 17 14 19 20 20 25  1  7 19]
 [10 13 13 22 27 20 21 28 12  4]
 [27 20 19 17 28  0 13  4  1 10]]

Basins:
  K     K     M     M     AI   (AI)   AE    A     A     A   
 (K)    K     M    (M)    M     Y    (AE)   AB    A     A   
  K     K    (AN)   M     Y    (Y)    AB   (AB)   A     A   
 (AJ)   AJ    X    (X)    X     C     C     A    (A)    A   
  B     B     B     X     C     C     C     T     A     A   
  B     B    (B)    B     C    (C)    C    (T)    T    (AR) 
  N     B     B     AA   (AA)   C    (AS)   T    (AK)   AK  
 (N)    N     B     L     AA    F     F     F     P     P   
  N     N     L    (L)    L     F    (F)    F    (P)    P   
  N    (AL)   AL    L     L     F     F     I     P     P   
  H     H     H     U    (AP)   F     I    (I)    I    (AO) 
  H    (H)    H    (U)    U     G     AF    I     I     I   
  AH    H     H     U     G     G    (AF)   V     W     W   
 (AH)   Q     H     G     G    (G)    G     V    (W)    W   
  Q    (Q)    Q     E     G     G     V    (V)    O    (AQ) 
  D     Q     AD    E     E     E     J     O    (O)    O   
 (D)    D    (AD)   E    (E)    J    (J)    J     O     O   
  D     D     AD    E     E     J     J    (Z)    Z     AG  
  D     D    (AC)   AC    E     R     R     Z     S    (AG) 
  D     D     AC   (AM)   R    (R)    R     S    (S)    S   

Letter  Size  Sink
 A      12    (3, 8) 
 B      10    (5, 2) 
 C       9    (5, 5) 
 D       9    (16, 0) 
 E       9    (16, 4) 
 F       9    (8, 6) 
 G       9    (13, 5) 
 H       9    (11, 1) 
 I       7    (10, 7) 
 J       6    (16, 6) 
 K       6    (1, 0) 
 L       6    (8, 3) 
 M       6    (1, 3) 
 N       6    (7, 0) 
 O       6    (15, 8) 
 P       6    (8, 8) 
 Q       5    (14, 1) 
 R       5    (19, 5) 
 S       4    (19, 8) 
 T       4    (5, 7) 
 U       4    (11, 3) 
 V       4    (14, 7) 
 W       4    (13, 8) 
 X       4    (3, 3) 
 Y       3    (2, 5) 
 Z       3    (17, 7) 
AA       3    (6, 4) 
AB       3    (2, 7) 
AC       3    (18, 2) 
AD       3    (16, 2) 
AE       2    (1, 6) 
AF       2    (12, 6) 
AG       2    (18, 9) 
AH       2    (13, 0) 
AI       2    (0, 5) 
AJ       2    (3, 0) 
AK       2    (6, 8) 
AL       2    (9, 1) 
AM       1    (19, 3) 
AN       1    (2, 2) 
AO       1    (10, 9) 
AP       1    (10, 4) 
AQ       1    (14, 9) 
AR       1    (5, 9) 
AS       1    (6, 6) 

示例5

输入:rainfall-example-5.txt 20x20地图,高度= 1000

示例6

输入:rainfall-example-6.txt 地图: 55x55,高度: 55^2

4.评论

  • 不喜欢使用chararray,因为它看起来是不可取的。我尝试在bool = string中使用一个数组,但当我试图更新该数组时,这给我带来了一个错误。
  • 我处理字符串和str_rep的方式是错误的。
  • 我的代码的结构感觉是正确的,但是类感觉非常空洞。
  • 我的代码与大型农地搏斗,这是rainfall-example-6.txt的一个例子。这是正常的,还是可以改进算法?
  • 没用的文件字符串?

5.代码

代码语言:javascript
复制
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import string
import numpy as np
from numpy import unravel_index

ALPHABETH = string.ascii_uppercase
ALPHABETH_len = len(ALPHABETH)


def num_2_alpha(num):
    '''
    Converts an arabic number 0, 1, 2.. to it's corresponding letter A, B, C, ....
    Example:
        0 > A
        1 > B
        26 > Z 
        27 > AA
    '''
    quotient, remainder = divmod(num, ALPHABETH_len)
    return quotient*ALPHABETH[0] + ALPHABETH[remainder]


def create_test_file(max_height, shape):
    '''
    Creates a random height map with dimensions x, y (from shape)
    and height from 0 to max_height.
    '''
    random_integers = np.random.randint(max_height, size=shape[0]*shape[1])
    return random_integers.reshape(shape[0], shape[1])


def format_topography(topography_):
    '''
    Inputs a typography of the farmland formated in a character array
    this function formats the typography into a nicer looking string. 
    Input
        [['(A)' 'A' '(B)']
         ['A' 'A' 'B']
         ['A' 'A' 'A']]
    Output:
        (A)  A  (B) 
         A   A   B  
         A   A   A  
    '''
    rows, columns = topography_.shape
    column_padding = [0]*columns

    for i in range(columns):
        column_padding[i] = len(max(topography_[:, i], key=len))

    padded_string = ''
    for i in range(rows):
        for j in range(columns):
            padded_string += ' {:^{}} '.format(
                topography_[i, j], column_padding[j])
        padded_string += '\n'
    return padded_string


def basin_2_string(basin_list):
    '''
    Input is a dictionary of basins where the key is the sink
    Example output:
        A: 7, Sink: (1, 2)
        B: 5, Sink: (0, 0)
        C: 4, Sink: (3, 3)
    '''

    letter_padding = len(num_2_alpha(len(basin_list)))
    sep1 = ' '*(len('letter')-letter_padding)

    size_padding = len(str(basin_list[0].size))
    sep2 = ' '*(len('Size')-size_padding)

    basin_string = 'Letter  Size  Sink\n'
    for i, basin in enumerate(basin_list):
        basin_string += '''{:>{}} {} {:{}d} {} {} 
'''.format(num_2_alpha(i), letter_padding, sep1, basin.size, size_padding, sep2, basin.sink)
    return basin_string


def create_height_map(filename):
    '''
    Input: a filename with a textfile formated as
    1 5 2 
    2 4 7 
    3 6 9
    Ouputs a matrix of the height map.
    '''
    file = open(filename, 'r')
    matrix = np.matrix([map(int, line.split()) for line in file])
    file.close()
    return matrix


def create_matrix_map(class_type, shape):
    '''
    Creates a dictionary where the keys are (x, y) coordinates. 
    This is used to store / index the basins and the cells
    '''
    length, width = shape
    matrix = dict()
    for i in xrange(length):
        for j in xrange(width):
            matrix[(i, j)] = class_type([i, j], [length, width])
    return matrix


def neighboors_list(coordinates, shape):
    '''
    Makes a list of all the neighboors to a point in the height map
    '''
    length, width = shape
    x, y = coordinates
    neighboors = []

    if x < 0 or x == length or y < 0 or y == width:
        ValueError("The coordinates lies outside the matrix")
    if x > 0:
        neighboors.append((x-1, y))
    if x + 1 < length:
        neighboors.append((x+1, y))
    if y > 0:
        neighboors.append((x, y-1))
    if y + 1 < width:
        neighboors.append((x, y+1))
    return neighboors


def create_basins_and_cells(height_map, shape):
    '''
    This creates the basins and the cells using the following algorithm:
    1. Each Cell keeps track of which Basin it belongs to; each Cell is initially assume to be in its own Basin. 
       Each Basin has a sink, or lowest Cell, which acts as a "representative element" of the Basin, 
       as well as a member count. Topography keeps track of all Basins.
    2. For each Basin, find lowest of the sink's neighbours. If the lowest is not already a member of this Basin, 
       transfer its cells into the lowest neighbour's Basin, and notify Topography that the higher basin no longer exists.
    3. Repeat step 2 until no further action is necessary.
    '''

    basins = create_matrix_map(Basin, shape)
    cells = create_matrix_map(Cell, shape)

    topography_changed = True
    while topography_changed:
        topography_changed = False

        for old_basin_coords in basins:
            sink_coords = basins[old_basin_coords].sink
            lowest_neighboor_height = height_map[sink_coords]
            lowest_neighboor_coords = sink_coords

            for neighboor in cells[sink_coords].neighboors:
                if height_map[neighboor] < lowest_neighboor_height:
                    lowest_neighboor_height = height_map[neighboor]
                    lowest_neighboor_coords = neighboor

            if lowest_neighboor_coords not in basins[old_basin_coords].cells:
                topography_changed = True
                new_basin_coords = cells[lowest_neighboor_coords].basin

                for cell_coords in basins[old_basin_coords].cells:
                    basins[new_basin_coords].cells.append(tuple(cell_coords))
                    cells[cell_coords].basin = new_basin_coords

                basins[new_basin_coords].size = len(
                    basins[new_basin_coords].cells)
                del basins[old_basin_coords]
                break

    basin_list = sorted(basins.values(), key=lambda x: x.size, reverse=True)
    return basin_list, cells


def create_topography(basin_list, shape):
    '''
    Enumerates the basins, in practice this creates the topography of the farmland
    '''
    character_length = len(num_2_alpha(len(basin_list)))
    topography = np.chararray(shape, itemsize=character_length+2)
    for i, basin in enumerate(basin_list):
        letter = num_2_alpha(i)
        for coords in basin.cells:
            if coords == basin.sink:
                topography[coords] = '('+letter+')'
            else:
                topography[coords] = letter
    return topography


class Cell():

    '''
    Simple class describing a single cell in the height map.
    '''

    def __init__(self, coordinates, shape):
        self.coordinates = tuple(coordinates)
        self.neighboors = neighboors_list(coordinates, shape)
        self.basin = tuple(coordinates)


class Basin():

    '''
    Simple class describing the basins in the height map. 
    '''

    def __init__(self, coordinates, shape):
        self.coordinates = tuple(coordinates)
        self.sink = tuple(coordinates)
        self.cells = [tuple(coordinates)]
        self.size = 1

    def __repr__(self):
        return '''<Size: {}, Sink: {}, Cells: {}>\n
        '''.format(self.size, self.sink, self.cells)


class Topography():

    '''
    A group of farmers has some elevation data, and we're going to help them understand 
    how rainfall flows over their farmland.

    We'll represent the land as a two-dimensional array of altitudes and use the following 
    model, based on the idea that water flows downhill:

    If a cell’s four neighboring cells all have higher altitudes, we call this cell a sink; water collects in sinks.

    Otherwise, water will flow to the neighboring cell with the lowest altitude. 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.

    Cells that drain into the same sink – directly or indirectly – are said to be part of the same basin.

    Your challenge is to partition the map into basins. In particular, given a map of elevations,
    your code should partition the map into basins and output the sizes of the basins, in descending order. 
    '''

    def __init__(self, filename):
        self.height_map = create_height_map(filename)
        self.shape = self.height_map.shape
        self.basins, self.cells = create_basins_and_cells(
            self.height_map, self.shape)
        self.topography = create_topography(self.basins, self.shape)
        self.basin_sizes = [basin.size for basin in self.basins]

    def __str__(self):
        string = '''
Height Farmland:
{}

Basins:
{}
{}'''.format(
            str(self.height_map),
            format_topography(self.topography),
            basin_2_string(self.basins))
        return string

if __name__ == '__main__':

    n = 50
    seperator = '-'*n
    print seperator
    for i in range(1, 5):
        print Topography('rainfall-example-{}.txt'.format(i))
        print seperator
    print
    # np.savetxt('rainfall-example-4.txt', create_test_file(30, (20, 10)), delimiter = ' ', fmt='%d')
    # np.savetxt('rainfall-example-5.txt', create_test_file(15, (30, 25)), delimiter = ' ', fmt='%d')
EN

回答 3

Code Review用户

回答已采纳

发布于 2016-08-19 18:46:22

类感觉是空的,因为基本上您只是在使用高级字典和一堆函数。不要误解我的意思--这基本上就是一个类,但是如果您要承诺使用类,那么您确实希望将它们中的功能封装起来。几乎所有的函数都应该成为类的实例方法。

我将概述您编写的代码,从入口点到末尾。

最大的问题是你的create_test_file

  1. 名字不好--更好的名字是create_test_matrix
  2. 坏的。它不能保证每个单元要么是一个接收器,要么有一个唯一的最小邻居。

我要做三件事来解决这个问题。

  1. 编写一个名为create_test_matrix的方法来生成矩阵
  2. create_test_file更改为实际写入有效的测试文件
  3. 使矩阵创建成为一个迭代过程--从左到右、从上到下(或任何您喜欢的方向)生成新的值。确保它们不会违反已经创建的值的约束,然后继续前进。

现在,我们实际上正在生成有效的测试文件,让我们看看剩下的代码。

你的Topography类有一个文件名,我觉得很奇怪。我希望Topography能够获取数据,并提供一个类方法来从文件中加载数据。这也意味着,通过测试,您不需要遍历中间文件。顺便说一句,您的实现是错误的(您的测试文件无效)。它们应该以矩阵的大小作为第一行,而您的测试文件没有它(而且您的代码不处理它)。

这个类方法最终将基本上是create_height_map,所以我将取出该函数的内容,并将其放在那里。在这样做时,我还将使用一个上下文管理器来安全地打开和关闭文件。我还将重命名文件对象变量,这样它就不会屏蔽内置的file。我还将使用列表理解代替map,因为它更Pythonic,更容易阅读。我忘记了np.matrix是否可以接受发生器对象,但如果可以,我将使用生成器理解而不是列表理解。

代码语言:javascript
复制
@classmethod
def from_file(cls, filename):
    with open(filename, 'r') as rainfall_data:
        data_iter = iter(rainfall_data)
        # skip the shape
        next(data_iter)
        rainfall_matrix = np.matrix(
            [[int(data) for data in line.split()]
             for line in data_iter]
        )
    return Topography(rainfall_matrix)

接下来,我将把create_basins_and_cells引入Topography,以及create_matrix_map

我从create_matrix_map开始。这可能只是一个字典的理解。我还将用元组交换列表,因为通常您应该更喜欢不可变。

代码语言:javascript
复制
@staticmethod
def create_matrix_map(cls, shape):
    length, width = shape
    return {(i, j): cls((i, j), shape) for i in xrange(length) for j in xrange(width)}

我使它成为一个静态方法,因为它不需要类或实例的任何内在属性。我仍然给它cls第一个论点,而不是class_type,因为这对我来说更容易理解- YMMV。

接下来,我将深入研究create_basins_and_cells。我不太喜欢你的算法--似乎你应该能够以一种更智能的方式迭代这些细胞。当我自己解决这个问题时,我用下降的高度对细胞进行分类,这就给了我一个非常干净的算法。但是,我的解决方案也遇到了性能问题,所以我将在这里提出一些新的建议(伪代码,因为我还没有完全完成代码)。

其目标是能够以任意顺序遍历所有单元格,而不必重复多次。要做到这一点,我认为我们想要把“创造盆地和细胞”阶段与“分类为正确的盆地”阶段结合起来。这可能看起来像这样(伪代码,我还没有完全弄清楚实际的代码)。

代码语言:javascript
复制
for row in topography
    for cell in row
        for each neighbor of cell
            if the neighbor feeds into this cell and has already been loaded
                add it to this cell's basin
        if the cell is a sink
            add it to an array of sinks
        else
            add this cell to the lowest neighbor (if it already has been loaded)

sizes = []
for sink in sinks
    count the number of connected components to that sink, append it to sizes

print sizes sorted in descending order, space separated

这仍然相当粗糙,但我认为我们可以通过只对数据进行一次传递就可以加快速度。我们还可以分阶段将数据加载到内存中,如果我们将这些计算结果存储在其他单元格上,那么我认为我们将不必在每个单元格上做太多额外的工作(这是计算中可以做的另一件事--很多计算是重复的,并且可以存储在单元格上)。我希望这个周末回到这个答案,修复这个部分并添加实际代码。

我会碰一下你的一些绳子来完成的。总之,这些都应该成为不同类的实例方法。您应该确保每个类都有自己的__str____repr____unicode__方法。然后,当你最终打印地形时,你不必担心盆地和细胞有合理的字符串表示,你所要做的就是担心填充。

另外,你最好的朋友将成为textwrap.dedent --当你使用多行字符串时,你不必做那么难看的不缩进。

票数 5
EN

Code Review用户

发布于 2016-08-05 16:07:36

小自动记账注意事项:你需要

代码语言:javascript
复制
basins[new_basin_coords].size = len(
                basins[new_basin_coords].cells)

但是,由于这种关系(盆地的大小总是其.cells的长度)是固定的,所以您应该在Basin对象的代码中使其自动:

代码语言:javascript
复制
@property
def size(self):
    return len(self.cells)

而且,你说得对,你的课程有点空旷。试着让它们自给自足。唯一调用create_topography的是Topography.__init__,所以可能将其移动到Topography.__init_topography。与create_height_mapcreate_basins_and_cellsneighbors_listbasin_2_stringformat_topography相似。

票数 3
EN

Code Review用户

发布于 2016-08-21 12:19:18

这个巧妙的小挑战有两个棘手的方面(就像他们在德语中所说的,‘Knack朋kte’):

  • 基于4个小区的局部邻域识别给定单元的接收器
  • 连通元件的识别

解决方案的正确性取决于正确处理这两件事--剩下的就是梦游。因此,重要的是将这两件事分开作为代码的焦点,这样它们才能被单独编码(和验证/测试)。

如果相关逻辑的某些部分分散在数十个工件(函数、结构、类)和数百行源代码中,这将是有害的。例如,我仍然没有理解原始Python解决方案的一些重要细节,尽管我怀疑这是不正确的,但我不能肯定地说。

因此,这里有一个替代方法的建议,它应该允许更好地分离关注点和更简单。

不相交-集联合

最简单、最有效的识别连接组件集合(“盆地”)的方法当然是不相交的集合森林,它只是一个功能很小的简陋阵列。请参阅维基百科中的不相交集数据结构或相关的黑客地球教程

因此,查找给定集合成员的集合代表('root')的函数的经典形式如下:

代码语言:javascript
复制
static int root (int[] a, int i)
{
    for (int j = a[i]; j != i; )
        a[i] = j = a[i = j];

    return i;
}

在查找根目录时,此函数还执行一些路径压缩,以加快进一步的搜索。这并不是使算法最优的全路径压缩(如Wikipedia文章中所解释的),因为这需要一个辅助堆栈或非常庞大的调用堆栈。但它确实以微不足道的成本改善了一切。

这里我提出了一个变体,其中设置的根槽用于跟踪成员数(存储为负数),而不是指向自己。这需要稍微修改根查找代码:需要引入一个步骤的滞后,因为根不再指向自己,因此它们的插槽内容不能再盲目地存储到其他插槽中。作为一个副作用,这种修改消除了经典版本的最终冗余存储:

代码语言:javascript
复制
static int root (int[] a, int i)
{
    int j = a[i];

    if (j >= 0)
        for (int k; (k = a[i = j]) >= 0; j = k)
            a[i] = k;

    return i;
}

在经典形式中,可以通过简单的赋值将由任意成员x和y标识的两个集合连接起来:

代码语言:javascript
复制
a[root(x)] = root(y);

有了会员数量,就有可能做Union by Rank,即总是将较小的集合附加到更大的集合,以便保持紧凑,并将路径压缩的工作负载降到最低。这确保了结构在重载下表现良好(尽管路径压缩不是很理想),因此值得为连接集创建一个单独的函数:

代码语言:javascript
复制
static void join (int[] a, int i, int j)
{
    if ((i = root(a, i)) != (j = root(a, j)))
    {
        if (a[i] <= a[j])  // the roots hold negative membership counts
        {
            a[i] += a[j];
            a[j] = i;
        }
        else
        {
            a[j] += a[i];
            a[i] = j;
        }
    }
}

这是连接组件分析完成和除尘,具有简单和(几乎)完美的效率。

小区局部邻域的

分析现在是邻里/水槽的分析。每个细胞的水槽是由它的近邻在指南针的四个点上决定的;这样确定的水槽是最终的--它永远无法改变。盆地成员资格可以在处理过程中发生变化,但不包括任何给定单元的接收器。因此,可以在输入的单个扫描中执行此分析,一次只在内存中保留三行(前一行、当前行和下一行)。 简化问题的一个简单方法是用无害的虚拟值填充地图的外部边缘,以减少需要单独处理的案例(边缘案例,字面意思是这样)。由于我们正在寻找最小值,如果填充单元格对其数据类型具有最大的可能值,则填充单元格是透明的。将坐标编码为row * column_count + column,可以减少杂乱,并将坐标映射到可直接与不相交的集合林一起使用的紧凑索引范围。 处理代码的核心是这个循环,它遍历当前行,查找每个单元格的接收器,并更新表示盆地成员资格的不相交集森林dsf[]: for (int col = 1; col <= col_count; ++col) { var n_w = Math.Min(prev_row[col], curr_row[col - 1]); var s_e = Math.Min(next_row[col], curr_row[col + 1]); var min = Math.Min(n_w, s_e); if (curr_row[col] > min) { int curr = (row - 1) * col_count + (col - 1), sink = curr; if (min == prev_row[col]) sink -= col_count; else if (min == next_row[col]) sink += col_count; else if (min == curr_row[col - 1]) sink -= 1; else sink += 1; join(dsf, curr, sink); } } 由于填充,列和行索引是基数1,因此在编码坐标时必须减去1。最小值的查找和相关坐标的确定是分开进行的,以获得更清晰和更紧凑的代码,这是必要的,因为C#缺乏Python在元组分配等方面的优雅。 其余的都是基本的,不值得谈论。请参阅CodeReview_Rainfall.cs on PasteBin,其中包含有条件的using指令,以便它可以与LINQPad (可以是免费下载)一起使用。为了完整起见,下面是如何按降序打印计数: var basins = new HashSet<int>(Enumerable.Range(0, dsf.Length).Select(i => root(dsf, i))); var counts = basins.Select(sink => -dsf[sink]).OrderBy(x => -x); Console.WriteLine(string.Join(" ", counts)); 仅仅是为了表明Python和Perl这样的语言不再垄断在完成一些事情上的小题大做。;-)

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/137837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档