小美的朋友关系(美团春招机试) Python AC代码
这道题网上已经有标准的解法了,就是反向并查集,但是很少看到能真正A掉的Python代码(C++最容易A)。主要原因可以归于以下四个原因:
1、节点数目最大可以到1e9,因此并查集初始化父节点时,千万不要每个节点都去初始化,很容易超时或者爆掉内存,使用HashMap去解决,只去初始化关系中有的节点。
2、被删除的关系可能原本就不存在,反向查询时删除操作是并查集中的添加操作,因此这种不存在的关系需要避免被添加到并查集中,没有这个操作的话结果会错误。
3、由于某些节点在初始化关系中是不存在的,因此查询时也会出现查询节点不再HashMap中,这个需要单独写代码去单独判断因此会额外增加计算开销,我的做法是不去判断是否在HashMap中,直接使用 Try...catch,这样不在HashMap中的节点会引发索引异常,但程序不会被终止掉,在catch中去添加否认的结果就行,省掉一部分判断计算成本。
4、最后的结果打印,因为查询最大可以到1e5的数量级别,使用循环print结果,IO开销太大了,会超时,我的做法是直接把结果拼成一个字符串,然后一次print,大幅削减IO开销。
这道题使用Python需要很多细节处理才行。
import sys
inputs = []
for line in sys.stdin:
inputs.append(line.split())
inputs = [list(map(lambda x: int(x), line)) for line in inputs]
n, m, q = inputs[0][0], inputs[0][1], inputs[0][2]
init_friendships = inputs[1:m + 1]
queries = inputs[m + 1:]
class UnionFind:
def __init__(self):
self.parents = {}
for i in range(m):
f = init_friendships[i]
self.parents[f[0]] = f[0]
self.parents[f[1]] = f[1]
def find(self, i):
if self.parents[i] != i:
self.parents[i] = self.find(self.parents[i])
return self.parents[i]
def union(self, i, j):
parent_i = self.find(i)
parent_j = self.find(j)
self.parents[parent_i] = parent_j
friendships = set()
for ship in init_friendships:
friendships.add(tuple(sorted(ship)))
for i in range(q):
q_tmp = queries[i]
if q_tmp[0] == 1:
if tuple(sorted(q_tmp[1:])) not in friendships:
queries[i] = None
for q in queries:
if q is not None and q[0] == 1:
friendships.discard(tuple(sorted(q[1:])))
union_find = UnionFind()
for ship in friendships:
union_find.union(*ship)
res = []
for q in queries[::-1]:
if q is not None:
if q[0] == 1:
union_find.union(q[1], q[2])
else:
try:
res.append('Yes' if union_find.find(q[1]) == union_find.find(q[2]) else 'No')
except BaseException:
res.append('No')
# for r in res[::-1]:
# print(r)
r = '\n'.join(res[::-1])
print(r)
