题目链接🔗:1402. 星空之夜 - AcWing题库
分析:
这题在笔者看来已经算是很难的题了...如果没学过图的哈希方法的话,很难做。
首先明确思路:遍历原图,遇到字符为1的位置就进行dfs搜索并记录该1连接的所有值为1的点,将这些坐标记录在queue里。
接下来是关键了:怎么判断该选择什么字母呢,也就是,怎么判断当前1组成的图案是否曾经出现过呢?这时候就需要引入图的哈希。
图的哈希也多种方式,这里使用的是将当前图案每两个点之间的距离之和作为这个图案的哈希值。
我们用hash_table储存所有哈希值,每当读如一个新图案时,需要遍历一下hash_table,若出现了这个图对应的哈希值,则说明这个图曾经出现过。注意这里哈希值因为是距离,所以是浮点数,由于计算机储存浮点数会有误差,所以不能直接用等于来进行比较两个浮点数,而是定义了一个小量,若这两个浮点数的差小于这个小量,则为相等。
剩下请看代码注释啦~
import math
import copy
W = int(input())
H = int(input())
Map = [] # 构造图
hash_table = [] # 列表当作哈希表使用,用于储存已出现过图案的哈希值
id = 0 # 已出现过的图案的数量
eps = 10**(-6) # 小值,用于浮点数比较
for i in range(H) : Map.append(list(input())) # 读图
Graph = copy.deepcopy(Map) # 复制一份图来写答案
def get_dist(node1,node2) : # 求两点之间的距离,这里node是元组
x1,y1 = node1
x2,y2 = node2
return math.sqrt((x1-x2)**2+(y1-y2)**2)
def get_hash() : # 获取哈希值,即该图案任意两点之间的距离之和
tot = 0
for i in range(top) :
for j in range(i+1,top) :
tot += get_dist(queue[i],queue[j])
return tot
def get_id(key) : # 获取哈希值对应的字母
global id,hash_table
for i in range(id) :
if math.fabs(hash_table[i]-key) < eps : return chr(i+ord('a')) # 如果该哈希值出现过,则返回对应的字母
id += 1 # 如果该哈希值没有出现过,则将其加入哈希表,并返回对应的字母
hash_table.append(key)
return chr(id-1+ord('a'))
def dfs(x,y) : # 深度优先搜索
global queue,top,Map
queue.append((x,y)) # 将当前点加入队列
top += 1 # 将队列长度加1
Map[x][y] = '0' # 将该点标记为已访问
for i,j in [(1,0),(0,1),(-1,0),(0,-1),(1,1),(-1,-1),(1,-1),(-1,1)] :
px = i + x
py = j + y
if px < 0 or px >= H or py < 0 or py >= W : continue
if Map[px][py] == '1' : dfs(px,py)
for i in range(H) :
for j in range(W) :
if Map[i][j] == '1' :
top = 0 # 这里记得要重置队列长度和队列 血的教训!!
queue = []
dfs(i,j)
tmp = get_id(get_hash()) # 获取哈希值对应的字母
for k in range(top) : # 更改答案
Graph[queue[k][0]][queue[k][1]] = tmp
for i in range(H) : # 输出答案
for j in range(W) :
print(Graph[i][j],end='')
print()