拓扑排序和floyed算法

1、拓扑排序:

链接

2、 floyed算法

 见链接

 

例题:

下面两道例题,重点看如何使用拓扑排序来解答,当然也可以使用floyed算法预计算

 

1、851. 喧闹和富有

有一组 n 个人作为实验对象,从 0 到 n - 1 编号,其中每个人都有不同数目的钱,以及不同程度的安静值(quietness)。为了方便起见,我们将编号为 x 的人简称为 "person x "。

给你一个数组 richer ,其中 richer[i] = [ai, bi] 表示 person ai 比 person bi 更有钱。另给你一个整数数组 quiet ,其中 quiet[i] 是 person i 的安静值。richer 中所给出的数据 逻辑自恰(也就是说,在 person x 比 person y 更有钱的同时,不会出现 person y 比 person x 更有钱的情况 )。

现在,返回一个整数数组 answer 作为答案,其中 answer[x] = y 的前提是,在所有拥有的钱肯定不少于 person x 的人中,person y 是最安静的人(也就是安静值 quiet[y] 最小的人)。

解答:

拓扑排序

如果 ai比 bi更有钱,我们从 ai​向 bi连一条有向边。这样得到的是一张有向无环图,因此我们从图上任意一点(设为 x)出发,沿着有向边所能访问到的点,拥有的钱都比 x 少。这意味着我们可以在计算出 answer[x] 后,用answer[x] 去更新 xx 所能访问到的点的 answer 值。

要实现这一算法,我们可以将每个answer[x] 初始化为 x,然后对这张图执行一遍拓扑排序,并按照拓扑序去更新 x 的邻居的 answer 值。通过这一方式我们就能将answer[x] 的值「传播」到 x 所能访问到的点上

 1 class Solution(object):
 2     def loudAndRich(self, richer, quiet):
 3         """
 4         :type richer: List[List[int]]
 5         :type quiet: List[int]
 6         :rtype: List[int]
 7         """
 8         n = len(quiet)
 9         graph = [[] for _ in range(n)]
10         res = [i for i in range(n)]
11         ind = [0 for _ in range(n)]
12 
13         for u, v in richer:
14             graph[u].append(v)
15             ind[v] += 1
16 
17         queue = deque([i for i in range(n) if ind[i] == 0])
18 
19         while queue:
20             u = queue.popleft()
21             for v in graph[u]:
22                 if quiet[res[u]] < quiet[res[v]]:
23                     res[v] = res[u]
24                 ind[v] -= 1
25                 if ind[v] == 0:
26                     queue.append(v)
27         return res

floyed,预计算解法

当然, 还是暴力打表法更直接。过程

  1. 构建一个图表示从i到j是否可达,默认为false
  2. 构建方式
    • 根据所给边来直接构建
    • 基于中间k点即Floyed方式来判断是否可达

注意,这题只是给个思路,暴力会超时,至少py会

 1 class Solution(object):
 2     def loudAndRich(self, richer, quiet):
 3         """
 4         :type richer: List[List[int]]
 5         :type quiet: List[int]
 6         :rtype: List[int]
 7         """
 8         n = len(quiet)
 9         dp = [[False for _ in range(n)] for _ in range(n)]
10         for i, j in richer:
11             dp[j][i] = True
12 
13         for i in range(n):
14             dp[i][i] = True
15 
16         for mid in range(n):
17             for i in range(n):
18                 for j in range(n):
19                     dp[i][j] = dp[i][mid] and dp[mid][j] or dp[i][j]
20 
21         res = []
22 
23         for i in range(n):
24             minNum = float('inf')
25             ind = i
26             for j in range(n):
27                 if dp[i][j]:
28                     if minNum > quiet[j]:
29                         minNum = quiet[j]
30                         ind = j
31             res.append(ind)
32 
33         return res

 

2、1462. 课程表 IV

你总共需要上 n 门课,课程编号依次为 0 到 n-1 。

有的课会有直接的先修课程,比如如果想上课程 0 ,你必须先上课程 1 ,那么会以 [1,0] 数对的形式给出先修课程数对。

给你课程总数 n 和一个直接先修课程数对列表 prerequisite 和一个查询对列表 queries 。

对于每个查询对 queries[i] ,请判断 queries[i][0] 是否是 queries[i][1] 的先修课程。

请返回一个布尔值列表,列表中每个元素依次分别对应 queries 每个查询对的判断结果。

注意:如果课程 a 是课程 b 的先修课程且课程 b 是课程 c 的先修课程,那么课程 a 也是课程 c 的先修课程。

 

拓扑排序

维护一个二维数组,存储节点之间的连接情况
构造拓扑排序,在构造过程中更新二维数组即可
 1 class Solution:
 2     def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]:
 3         """
 4         :type numCourses: int
 5         :type prerequisites: List[List[int]]
 6         :type queries: List[List[int]]
 7         :rtype: List[bool]
 8         """
 9         graph = [[] for _ in range(numCourses)]
10         ind = [0 for _ in range(numCourses)]
11 
12         connected = [[False for _ in range(numCourses)] for _ in range(numCourses)]
13 
14         for i in range(numCourses):
15             connected[i][i] = True
16 
17         for u, v in prerequisites:
18             graph[u].append(v)
19             ind[v]+=1
20         
21         q = deque([i for i in range(numCourses) if ind[i] == 0])
22 
23         topo = []
24 
25         while q:
26             cur = q.popleft()
27             topo.append(cur)
28             for i in graph[cur]:
29                 ind[i] -= 1
30                 
31                 # 如果 j 到 cur 有链接 而 cur 到 i 有链接 所以 j 到 i 有链接 
32                 for j in topo:
33                     if connected[j][cur]:
34                         connected[j][i] = True
35 
36                 if ind[i] == 0:
37                     q.append(i)
38 
39         res = []
40         for i, j in queries:
41             res.append(connected[i][j])
42 
43         return res        

 

 

floyed预计算解法、

过程同上

 1 class Solution:
 2     def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]:
 3         """
 4         :type numCourses: int
 5         :type prerequisites: List[List[int]]
 6         :type queries: List[List[int]]
 7         :rtype: List[bool]
 8         """
 9         dp = [[False for _ in range(numCourses)] for _ in range(numCourses)]
10 
11         for r, c in prerequisites:
12             dp[r][c] = True
13 
14         for mid in range(numCourses):
15             for i in range(numCourses):
16                 for j in range(numCourses):
17                     if dp[i][mid] and dp[mid][j]:
18                         dp[i][j] = True
19 
20         res = []
21         for q, p in queries:
22             res.append(dp[q][p])
23 
24         return res

 

posted @ 2021-12-15 22:29  r1-12king  阅读(77)  评论(0编辑  收藏  举报