运行要求
运行时间限制: 2sec
内存限制: 1024MB
原文链接
题目
有一个社交网络APP,注册的用户有用户1,用户2,用户3....用户N
这N个用户之间,有M组好友关系,N组黑名单关系
对于i = 1,2,3,4...M,用户Ai和用户Bi是【双向好友】关系
对于i = 1,2,3,4...K,用户Ci和用户Di是【双向拉黑】关系
以下4个条件都满足的话,用户a和用户b就是【推荐好友】的关系
- a!=b
- a和b不是【双向拉黑】关系
- a和b不是【双向好友】关系
- 对于大于1,小于等于N的整数L,存在数列c0,c1,c2,c3...cL. c0 = a, cL = b.对于i=0,1,2,3,4,...,i-1,用户i和用户i+1是好友关系
对于i=1,1,2,3,4,...N 求出用户i的推荐好友数
输入前提条件
- 输入的都为整数
- 2<=N<=100000
- 0<=M<=100000
- 0<=K<=100000
- 1<=Ai,Bi<=N
- Ai != Bi
- 1<=Ci,Di<=N
- Ci != Di
- (Ai,Bi) != (Aj,Bj) (i!=j)
- (Ai,Bi) != (Bj,Aj) (i!=j)
- (Ci,Di) != (Cj,Dj) (i!=j)
- (Ci,Di) != (Dj,Cj) (i!=j)
- (Ai,Bi) != (Cj,Dj) (i!=j)
- (Ai,Bi) != (Dj,Cj) (i!=j)
输入
输入都以以下标准从命令行输入
N M K
A1 B1
.
.
.
AM BM
C1 D1
.
.
.
CK DK
输出
输出每个用户的推荐好友数,用空格分开
例1
输入
4 4 1
2 1
1 3
3 2
3 4
4 1
输出
0 1 0 1
用户2和用户3是好友关系,用户3和用户4是好友关系,再加上用户2和用户3之间不存在拉黑关系,所以用户2和用户4是【推荐好友】的关系
用户1和用户3因为是好友关系,所以不是【推荐好友】关系
所以只有用户2和用户4之间存在【推荐好友】关系
例2
输入
5 10 0
1 2
1 3
1 4
1 5
3 2
2 4
2 5
4 3
5 3
4 5
输出
0 0 0 0 0
所有的用户都是好友关系,所以所有的用户没有【推荐好友】
例3
输入
10 9 3
10 1
6 7
8 2
2 5
8 4
7 3
10 9
6 4
5 8
2 6
7 5
3 1
输出
1 3 5 4 3 3 3 3 1 0
读懂题目
有一个说法,地球上通过6个人就能够认识世界上任何一个人。
可以把这个题目抽象成一个树的题目
如例3
解题思路
1.如上图所示,把好友关系抽象成为一个树形结构后,树形结构就有两个小团体。
2.我们细看树上的每一个点,会总结出这么一个规律。
每个顶点的的推荐好友的数量 = 所在的团体的成员数 - 直接好友数 - 统一团体内的拉黑的好友数 - 1(自身)
3.直接好友数很容易求出来,输入里面给出了数组,我们直接统计一下就好
4.所在的团体的成员数怎么求出来。
这里有两种思路
思路1. dfs或者bfs遍历,任意找一个点为起始点开始遍历,遍历到的顶点打一标签A。然后以还没有被遍历到的顶点为起始点遍历,对遍历到的顶点打标签B,这样遍历,直到所有的点都被遍历了。
思路2. Union Find.具体Union Find的解析,请参考下面的这篇文章
数据结构 - Union Find #3
代码
思路1的代码:
BFS遍历给每个节点打标签
结果是TLE很遗憾
from collections import deque
S = input().split(" ")
N = int(S[0])
M = int(S[1])
K = int(S[2])
ARR = []
BRR = []
for i in range(M):
ARR.append([int(s) for s in input().split(" ")])
for i in range(K):
BRR.append([int(s) for s in input().split(" ")])
def prepare(n, arr):
nodes = [[] for i in range(n)]
nodeStates = [False for i in range(n)]
nodeLabels = [0 for i in range(n)]
for ar in arr:
fromNode = ar[0] - 1
toNode = ar[1] - 1
nodes[fromNode].append(toNode)
nodes[toNode].append(fromNode)
return nodes, nodeStates, nodeLabels
def prepare2(n,brr):
nodes = [[] for i in range(n)]
for ar in brr:
fromNode = ar[0] - 1
toNode = ar[1] - 1
nodes[fromNode].append(toNode)
nodes[toNode].append(fromNode)
return nodes
def calculate(n, m, k, nodes, nodeStates, nodeLabels):
q = deque()
label = 0
labelDict = {}
while nodeStates.count(False) > 0:
falseIndex = nodeStates.index(False)
q.append(falseIndex)
while len(q) > 0:
node = q.popleft()
if nodeStates[node] == True:
continue
nodeStates[node] = True
nodeLabels[node] = label
childNodes = nodes[node]
if labelDict.get(label) == None:
labelDict.__setitem__(label,1)
else:
labelDict.__setitem__(label,labelDict.get(label)+1)
for childNode in childNodes:
if nodeStates[childNode] == False:
q.append(childNode)
label = label + 1
result = []
for i in range(n):
l = nodeLabels[i]
s = 0
for blockNode in blockNodes[i]:
if nodeLabels[blockNode] == l:
s = s + 1
result.append(str(labelDict[l] - len(nodes[i]) - 1 - s))
print(" ".join(result))
nodes, nodeStates, nodeLabels = prepare(N, ARR)
blockNodes = prepare2(N,BRR)
calculate(N, M, K, nodes, nodeStates, nodeLabels)
思路2的代码:
class UnionFind():
def __init__(self, n):
self.n = n
self.parents = [-1] * n
def find(self, x):
if self.parents[x] < 0:
return x
else:
self.parents[x] = self.find(self.parents[x])
return self.parents[x]
def union(self, x, y):
x = self.find(x)
y = self.find(y)
if x == y:
return
if self.parents[x] > self.parents[y]:
x, y = y, x
self.parents[x] += self.parents[y]
self.parents[y] = x
def size(self, x):
return -self.parents[self.find(x)]
def same(self, x, y):
return self.find(x) == self.find(y)
def members(self, x):
root = self.find(x)
return [i for i in range(self.n) if self.find(i) == root]
def roots(self):
return [i for i, x in enumerate(self.parents) if x < 0]
def group_count(self):
return len(self.roots())
def all_group_members(self):
return {r: self.members(r) for r in self.roots()}
def __str__(self):
return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())
N,M,K = list(map(int,input().split()))
ARR = []
for i in range(M):
ARR.append(list(map(int,input().split())))
BRR = []
for i in range(K):
BRR.append(list(map(int,input().split())))
unionFind = UnionFind(N)
fl = [[] for i in range(N)]
bl = [[] for i in range(N)]
for ar in ARR:
fromNode = ar[0] - 1
toNode = ar[1] - 1
unionFind.union(fromNode, toNode)
fl[fromNode].append(toNode)
fl[toNode].append(fromNode)
for br in BRR:
fromNode = br[0] - 1
toNode = br[1] - 1
bl[fromNode].append(toNode)
bl[toNode].append(fromNode)
result = []
for i in range(N):
size = unionFind.size(i) - 1
for f in fl[i]:
if unionFind.same(i,f):
size = size - 1
for b in bl[i]:
if unionFind.same(i,b):
size = size - 1
result.append(str(size))
print(" ".join(result))
总结
这道题考察了如何把问题抽象成数的模型去解决问题
每个顶点的的推荐好友的数量 = 所在的团体的成员数 - 直接好友数 - 统一团体内的拉黑的好友数 - 1(自身)
意识到上面的公式是关键
还有就是对必要的算法union find的考察
※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。