学习流程
知道最小不相交路径覆盖和最小可相交路径覆盖的概念
https://blog.csdn.net/dajiangyou123456/article/details/108004672
看懂匈牙利算法:
https://blog.csdn.net/Arabic1666/article/details/79824390
利用匈牙利算法做一道“最小不相交路径覆盖的题目”:
http://poj.org/problem?id=1422
"""
题目描述:
有n个十字路口(0,1,...,n-1),m个街道,每一个街道连接两个十字路口。一个空降伞兵,随机选择一个没有被访问过的十字路口降落,并按照街道去访问其它没有被访问过的十字路口。问:最少需要几个伞兵,才能够
无重复地把所有路口访问完。
思路:
把每一个路口看作是节点,利用匈牙利算法。具体为:
遍历每一个路口,进入递归程序。对于路口i,遍历它能够到达的路口j,如果当前递归中,路口j还没有被用过,则标记为用过,并判断1. 路口j是不是还没有跟别的路口匹配 2. 和路口j匹配的那一个别的路口x,是否可以
找到其它可以匹配的路口。满足1或2,则j与i匹配,递归结果返回True;如果每一个能够到达的路口j都不能和i匹配,则递归结果返回False。
记录所有的匹配数,最终的伞兵数 = 十字路口数 - 匹配数
"""
def dfs(now_node, n):
for neighbour_node in range(1, n+1):
if graph[now_node][neighbour_node] == 0:
continue
if used[neighbour_node] == 0:
used[neighbour_node] = 1
if match[neighbour_node] == -1 or dfs(match[neighbour_node], n):
match[neighbour_node] = now_node
return True
return False
T = int(input()) # 样例数
while T!= 0:
T -= 1
n = int(input()) # 十字路口数
m = int(input()) # 街道数
graph = [[0 for i in range(n+1)] for j in range(n+1)]
match = [-1 for i in range(n+1)]
used = [0 for i in range(n+1)]
for i in range(m):
u, v = list(map(int, input().split()))
graph[u][v] = 1 # DAG
cot = 0
for i in range(1,n + 1):
used = [0 for i in range(n+1)] # 清空当前递归的used列表
if dfs(i, n):
cot += 1
print(n - cot)
看懂弗洛伊德算法:
https://www.cnblogs.com/wangyuliang/p/9216365.html
理解最小可相交路径覆盖向最小不相交路径覆盖的转化(基于弗洛伊德算法):
https://blog.csdn.net/dajiangyou123456/article/details/108004672
明确此情境下的DAG中的边并没有权重,所以此情境下的弗洛伊德代码如下:
"""
弗洛伊德
"""
def floyd(n):
for k in range(1, n + 1): # 当前考虑的中间节点
for i in range(1, n + 1): # 遍历图中的每一个节点
for j in range(1, n + 1):# 考虑该节点的所有可能的邻接节点
if graph[i][k] * graph[k][j] == 1:
graph[i][j] = 1
n = int(input()) # 十字路口数
m = int(input()) # 街道数
graph = [[0 for i in range(n+1)] for j in range(n+1)]
for i in range(m):
u, v = list(map(int, input().split()))
graph[u][v] = 1 # DAG
floyd(n)
print(graph)
最后,做一下蓝桥杯的“估计人数”
https://blog.csdn.net/qq_43319748/article/details/109679073
完成:最小不相交的路径覆盖–Flyod–>最小可相交的路径覆盖–匈牙利算法–>解
# 弗洛伊德
def floyd(n):
for k in range(1, n + 1): # 当前考虑的中间节点
for i in range(1, n + 1): # 遍历图中的每一个节点
for j in range(1, n + 1):# 考虑该节点的所有可能的邻接节点
if new_graph[i][k] * new_graph[k][j] == 1:
new_graph[i][j] = 1
# 匈牙利
def dfs(node, node_cot):
for k in range(1, node_cot+1):
if new_graph[node][k] == 1:
if visited[k] == 0:
visited[k] = 1
if connected[k] == -1 or dfs(connected[k] ,node_cot):
connected[k] = node
return True
return False
dx = [0, 1]
dy = [1, 0]
N, M = list(map(int, input().split()))
graph = [[0 for i in range(M)] for j in range(N)]
node_cot = 0
for i in range(N):
strr = input()
for j in range(M):
e = int(strr[j])
if e == 1:
node_cot += 1
graph[i][j] = [e, node_cot]
else:
graph[i][j] = [e, -1]
new_graph = [[0 for i in range(node_cot + 1)] for j in range(node_cot + 1)]
for i in range(N):
for j in range(M):
if graph[i][j][0] == 1:
node_idx = graph[i][j][1]
for x in range(2):
new_i = i + dx[x]
new_j = j + dy[x]
if 0 <= new_i < N and 0 <= new_j < M and graph[new_i][new_j][0] == 1:
new_graph[node_idx][graph[new_i][new_j][1]] = 1
floyd(node_cot)
cot = 0
visited = [0 for i in range(node_cot + 1)]
connected = [-1 for i in range(node_cot + 1)]
for i in range(1, node_cot + 1):
visited = [0 for i in range(node_cot + 1)]
if dfs(i, node_cot):
cot += 1
print(node_cot - cot)