google code jam exercise——Water Sheds

Water Sheds,这是Qualification Round 2009的第二道题,还没有想到好的解决办法的时候,直接看了参考解答。参考解答研究了好久才看明白,看来还需要加强练习。

先来看看题目意思,给定一个mxn的矩阵,每个位置是一个海拔值,相当于是一份地图,要求根据水流给这份地图进行标注,水流动的规则是,

1. 对任一个位置,至多流向它的四个邻居中的一个,邻居就是东南西北方向的四个位置;

2. 如果相比于四个邻居,它本身的海拔最低,那么水不流动,这个位置称为sink,盆地;

3. 否则,水流向海拔最低的一个邻居;

4. 选择海拔最低的邻居的顺序是,North,West,East,South,即北,西,东,南。

解题步骤如下:

0. 初始化当前label="a"

1. 遍历地图中所有位置,对任一位置(ui,uj),寻找它所在的盆地;

2. 寻找盆地的方法,以(i,j)=(ui,uj)为起始点,找四个邻居中最小的一个,如果没有比它更小的,即找到了相应的盆地(i,j);

3. 如果四个邻居中有更小的(nexti,nextj),那么继续以(i,j)=(nexti,nextj)为起始点寻找盆地。

4. 找到相应的盆地(i,j)之后,查看(i,j)位置是否已经标注,如果没有,则将其标注为当前label,并且,label=label+1;

5. (ui,uj)即得到与(i,j)相同的标注

代码如下:

#/usr/bin/python
#
encoding:UTF-8
#
Filename:WaterSheds_Ref.py

import sys

def ReadInts():
return list(map(int, sys.stdin.readline().strip().split(" ")))

def Cross(a, b):
for i in a:
for j in b:
yield (i, j)

def Neighbours(ui, uj, m, n):
if ui - 1 >= 0: yield (ui - 1, uj)
if uj - 1 >= 0: yield (ui, uj - 1)
if uj + 1 < n: yield (ui, uj + 1)
if ui + 1 < m: yield (ui + 1, uj)

fin = open(sys.argv[1])
sys.stdin = fin

fout = open(sys.argv[1].replace(".in",".out"),"w")

N = ReadInts()[0]
for prob in xrange(1, N + 1):
# Read the map
(m, n) = ReadInts()
maze = [ReadInts() for _ in xrange(m)]
answer = [["" for _ in xrange(n)] for _ in xrange(m)]
# The map from sinks to labels.
label = {}
next_label = 'a'
# Brute force each cell.
for (ui, uj) in Cross(xrange(m), xrange(n)):
(i, j) = (-1, -1)
(nexti, nextj) = (ui, uj)
while (i, j) != (nexti, nextj):
(i, j) = (nexti, nextj)
for (vi, vj) in Neighbours(i, j, m, n):
if maze[vi][vj] < maze[nexti][nextj]:
(nexti, nextj) = (vi, vj)

# Cell (ui, uj) drains to (i, j).
if (i, j) not in label:
label[(i, j)] = next_label
next_label = chr(ord(next_label) + 1)
answer[ui][uj] = label[(i, j)]

# Output the labels.
#
print "Case #%d:" % prob
an = "Case #%d:\n" % prob
for i in xrange(m):
# print " ".join(answer[i])
an = an + " ".join(answer[i])
an = an + "\n"
fout.write(an)

fin.close()
fout.close()

关于代码的几点解释:
1. sys.stdin=fin

在Contest Analysis给出的参考程序中,ReadInts直接从stdin读取数据,而我一般习惯从文件读取测试数据,所以使用了重定向,在C/C++里面是可以这样用的,所以试了一下,发现这里也可以这样用。

2. ReadInts

这是读取输入数据的函数,一句话就解决了,之前我都是先line=fin.readline(),然后去掉line最后的"\n",然后使用split分割,最后将字符串转换成int,很多条语句,这里一行就搞定了。这种写法很好玩的。

3. yield

这是一种更好玩的写法。虽然是把这里的程序看懂了,但如何使用yield还是不熟悉,以后可以多练习。

一切愉快!

posted @ 2012-04-08 20:52  Frandy.CH  阅读(303)  评论(0编辑  收藏  举报