Acwing:星空之夜(图的哈希 Python)

 题目链接🔗: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()
        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UESTC_KS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值