运行要求
运行时间限制: 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

名称未設定.001.jpeg

解题思路

1.如上图所示,把好友关系抽象成为一个树形结构后,树形结构就有两个小团体。
名称未設定.002.jpeg

2.我们细看树上的每一个点,会总结出这么一个规律。
每个顶点的的推荐好友的数量 = 所在的团体的成员数 - 直接好友数 - 统一团体内的拉黑的好友数 - 1(自身)

名称未設定.003.jpeg
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的考察

※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
二维码.jpg



伟大不DIAO
1 声望1 粉丝

Done is better than perfect