> For the complete documentation index, see [llms.txt](https://cai-sen-se.gitbook.io/leetcode/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cai-sen-se.gitbook.io/leetcode/2001-3000/2076.-chu-li-han-xian-zhi-tiao-jian-de-hao-you-qing-qiu.md).

# 2076.处理含限制条件的好友请求

<https://leetcode-cn.com/problems/process-restricted-friend-requests/>

## 一、并查集

```python
class UnionFind:
    # 构造函数传入totalNodes为总节点数
    def __init__(self, totalNodes):
        # parents[i]表示i的根，初始i的根为其自身
        self.parents = [i for i in range(totalNodes)]
        # 连通分量数
        self.count = totalNodes
        # 连通分量大小，即树的“重量”
        self.size = [1] * totalNodes
    # 合并连通区域是通过find来操作的, 即看这两个节点是不是在一个连通区域内.
    def union(self, node1, node2):
        root1 = self.find(node1)
        root2 = self.find(node2)
        # 不连通才合并
        if root1 != root2:
              # 小树合并到大树
            if self.size[root1] > self.size[root2]:
                self.parents[root2] = root1
                self.size[root1] += self.size[root2]
            else:
                self.parents[root1] = root2
                self.size[root2] += self.size[root1]
            # 连通分量数减一
            self.count -= 1

    # 查找最终的根
    def find(self, node):
        while self.parents[node] != node:
            self.parents[node] = self.parents[self.parents[node]]
            node = self.parents[node]
        return node

    # 判断两个点是否连通
    def isConnected(self, node1, node2):
        return self.find(node1) == self.find(node2)

    # 返回连通分量个数
    def count(self):
        return self.count
    
```

算法：每轮将前i个（i从0到n-1）好友请求（设为\[a,b]）写入并查集，即把a，b连通。然后用限制集中的每个限制关系c、d进行测试，若c与d连通，说明这i个请求不能成立（确切的说是第i个）

```python
class Solution:
    def friendRequests(self, n: int, restrictions: List[List[int]], requests: List[List[int]]) -> List[bool]:
        res = []
        passIndex = set()		#标记不能成立的请求
        for i in range(len(requests)):
            uf = UnionFind(n)	#每轮创建一个并查集
            for j in range(i+1):
                if j in passIndex:	#若该请求被标记不能成立，则跳过
                    continue
                a, b = requests[j][0], requests[j][1]
                uf.union(a,b)
            flag = True
            for c, d in restrictions:	#测试所有限制条件
                if uf.isConnected(c, d):
                    flag = False
                    passIndex.add(i)
                    break
            res.append(flag)
        return res 
```

## 优化

每个集合内都是直接朋友或者间接朋友。

对于：`x = requests[i][0], y = requests[i]` 如果x所处的集合与y所处的集合相等，这样就意味着x和y已经是朋友了 如果x所处的集合与y所处的集合不等，需要判断x所处的集合与y所处的集合能否合并，可以遍历restrictions，具体如下：

对于：`p = restrictions[j][0], q = restrictions[j][1]`有以下两种情况不合符条件 如果x与p在同一个集合 且 q与y在同一个集合 如果y与p在同一个集合 且 x与q在同一个集合 上面两种情况都说明，若x与y成为朋友，则p和q成为间接朋友，这是限制条件不允许的

```python
# 并查集模板略
class Solution:
    def friendRequests(self, n: int, restrictions: List[List[int]], requests: List[List[int]]) -> List[bool]:
        res = []
        uf = UnionFind(n)
        for x, y in requests:
            flag = True
            if not uf.isConnected(x, y):
                for p, q in restrictions:
                    if uf.isConnected(p, x) and uf.isConnected(q, y) or uf.isConnected(q, x) and uf.isConnected(p, y):
                        flag = False
                        break
            if flag:
                uf.union(x, y)
            res.append(flag)
        return res
```
