[蓝桥杯]——估计人数之最小路径覆盖问题

学习流程

知道最小不相交路径覆盖和最小可相交路径覆盖的概念
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)

猜你喜欢

转载自blog.csdn.net/jokerxsy/article/details/117561030
今日推荐