【最小路径覆盖】最小路径覆盖

算法实现题8-3 最小路径覆盖问题(习题 8-13)
´问题描述:
给定有向图 G=(V,E)。设 P 是 G 的一个简单路(顶点不相交)的集合。如果 V 中每个
顶点恰好在 P 的一条路上,则称 P是 G 的一个路径覆盖。P 中路径可以从 V 的任何一个顶
点开始,长度也是任意的,特别地,可以为0。G 的最小路径覆盖是 G 的所含路径条数最少
的路径覆盖。
设计一个有效算法求一个有向无环图G 的最小路径覆盖。
提示:设V={1,2,º ,n},构造网络G1=(V1,E1)如下:
{ } { } n n y y y x x x , , , , , , V1 1 0 1 0   » = ,
{ } { } { } E j i y x V i y y V i x x j i i i
Œ » Œ » Œ = ) . ( : ) , ( : ) , ( : ) , ( E1 0 0  
每条边的容量均为1。求网络G1的( 0 x ,
0 y )最大流。
´编程任务:
对于给定的给定有向无环图G,编程找出 G的一个最小路径覆盖。
´数据输入:
由文件input.txt提供输入数据。文件第1 行有 2个正整数 n和 m。n是给定有向无环图
G 的顶点数, m是G 的边数。 接下来的m行, 每行有 2 个正整数 i和 j, 表示一条有向边(i,j)。  
´结果输出:
程序运行结束时,将最小路径覆盖输出到文件 output.txt 中。从第 1 行开始,每行输出


有两种解法:

1、网络流。不懂

2、二分图匹配。


很好理解。。把一个点拆成两个点,并分成二分图。原来(i,j)∈E0,则(i,j')属于E。

求一个最大匹配。如果左半集中一个点i与右半集j'中一个点匹配,认为j‘是i的后继(因为在这个问题中,一个点一定只有一个后继!!)

最后我们容易得出,如果i有后继,i'无前驱,则表明i是一条路径的起点。如果i有后继且i'有前驱,则i是路径中的点。如果i无后继,而i'有前驱则i是终点。

我们找到所有终点即路径数。等于总结点数减去最大匹配数。

#include <cstring>
#include <cstdio>

struct node
{
	long ind;
	node* nxt;	
};
node* head[100000];
bool vis[100000];
long lnk[100000];
long ans = 0;
long to[100000];

void insert(long a,long b)
{
	node* nn = new node;
	nn -> ind = b;
	nn -> nxt = head[a];
	head[a] = nn;	
}

bool Hungary(long u)
{
	for (node* vv=head[u];vv;vv=vv->nxt)
	{
		long v = vv -> ind;
		if (!vis[v])
		{
			vis[v] = true;
			if (!lnk[v]||Hungary(lnk[v]))
			{
				lnk[v] = u;
				return true;
			}		
		}	
	}
	return false;
}

int main()
{
	freopen("path.in","r",stdin);
	freopen("path.out","w",stdout);
	
	long n;long m;
	scanf("%ld%ld",&n,&m);
	for (long i=1;i<m+1;i++)
	{
		long i;long j;
		scanf("%ld%ld",&i,&j);
		insert(i,j);
	}   
    for (long i=1;i<n+1;i++)
    {
		memset(vis,0,sizeof vis);
		if (Hungary(i)) ans++;
	}
	for (long i=1;i<n+1;i++)
	{
		to[lnk[i]] = i;	
	}
	for (long i=1;i<n+1;i++)
	{
		if (to[i] && !lnk[i])
		{
			long ths = i;
			while (ths)
			{
				printf("%ld ",ths);
				ths = to[ths];
			}
			printf("\n");
		}
	}
	printf("%ld",n-ans);
	return 0;
}


最小路径覆盖是指在一个加权有向图中找到一条从源节点(起始点)到目标节点(结束点)的路径,该路径恰好经过图中的每一条边一次。在Python中,可以使用迪杰斯特拉算法(Dijkstra's Algorithm)或者贝尔曼-福特算法(Bellman-Ford Algorithm)作为基础,结合贪心策略来找出这样的路径。 这里是一个基本的使用迪杰斯特拉算法实现最小路径覆盖的例子: ```python from heapq import heappop, heappush def shortest_path_with_coverage(graph, start, end): INF = float('inf') # 定义无穷大 dists = {node: INF for node in graph} # 初始化距离字典 prev_nodes = {node: None for node in graph} # 初始化前驱节点字典 dists[start] = 0 # 设置起点的距离为0 queue = [(0, start)] # 使用堆来存储节点及其距离 while queue: curr_dist, curr_node = heappop(queue) # 取出距离最小的节点 # 如果已经访问过更短路径,则跳过当前节点 if dists[curr_node] < curr_dist: continue # 更新相邻节点的距离和前驱节点 for neighbor, weight in graph[curr_node].items(): new_dist = curr_dist + weight if new_dist < dists[neighbor]: dists[neighbor] = new_dist prev_nodes[neighbor] = curr_node heappush(queue, (new_dist, neighbor)) # 将更新后的节点加入堆 # 从终点开始构建路径 path = [] curr_node = end while curr_node is not None: path.append(curr_node) curr_node = prev_nodes[curr_node] path.reverse() # 路径需要从终点反向 return path, dists[end] # 返回路径和总距离 # 示例图,假设这是一个有向图 graph = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'D': 5}, 'C': {'A': 4, 'D': 1}, 'D': {'B': 5, 'C': 1, 'E': 6}, 'E': {} } start = 'A' end = 'E' result = shortest_path_with_coverage(graph, start, end) path, total_cost = result print("最小路径覆盖:", path) print("总覆盖成本:", total_cost)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值