Codeforces#303-E - Paths and Treesg-最短路+最小生成树

该博客介绍了Codeforces上的一道问题,涉及无向图的最短路径和最小生成树。题目要求找到一个子图,其中起点U到所有点的最短路径保持不变,同时边权和最小。解决方法包括先求最短路,再遍历边以更新子图,最终实现总复杂度为(n+m)log(n)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://codeforces.com/contest/545/problem/E


题意:给一个无向图G,一个起点U,要求找到一个子图,【子图中U到各点的最短路与原图相等】,求出  【所有边权之和最小的】 一个子图

输出权值和 +每条边的编号 (边按输入的顺序从一到m编号)


思路:直接求一遍最短路,得到dist[]数组

然后

 for (i=1;i<=n; i++)

{

//遍历与点i相连的所有边,如果能找到一条 边使得  【起点到i 点 的dist不变】且 【边权比原来的小】,就更新掉子图的边

}

求最小权值和这部分复杂度O(m)

求最短路(n+m)log(n)

总复杂度还是(n+m)log(n)......




#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
#define INF 9223372036854775807
const __int64 maxn = 300005;
struct EDGE 
{
	__int64 u;
	__int64 x;__int64 v;
	int id;
	EDGE(){}
	EDGE (__int64 uu,__int64 i,__int64 j,__int64 idd)
	{
		u=uu;  x=i;v=j; id=idd;
	}
	bool operator < (const EDGE &b) const
	{
		return v>b.v;
	}
};
vector <EDGE> tm[maxn];
vector <int> ans;
 
__int64 dist[maxn]; 
priority_queue<EDGE> que;
int main()
{
	__int64 n,r,i,j;
	__int64 a,b,c;
	scanf("%I64d%I64d",&n,&r);
	for (i=1;i<=n;i++)
		dist[i]=INF; 
	for (i=1;i<=r;i++) 
	{
		scanf("%I64d %I64d %I64d",&a,&b,&c); 
		tm[a].push_back(EDGE(a,b,c,i));
		tm[b].push_back(EDGE(b,a,c,i)); 
	}
	__int64 st;
	scanf("%I64d",&st); 
	dist[st]=0;
	  	que.push(EDGE(st,st,0,-1));	 
		__int64 minway;
		__int64 minpoint;
									// --------------------Dijkstra 
		while(!que.empty())
		{
			EDGE p=que.top();
			que.pop();
			minpoint=p.x;
			minway=p.v; 
		//	vis[minpoint]=1;//参见spfa(),用vis是把已经在queue中的点不用再push,但是此处用邻接表无法解决重边的问题,所以需要多次push,也就是不能用vis
			for (i=0;i<tm[minpoint].size();i++)
			{
				__int64 x=tm[minpoint][i].x;
				__int64 v=tm[minpoint][i].v;

				if ( v+minway<dist[x]  /*&&vis[x]!=1*/ ) 
				{
					dist[x]=v+minway; 
			    	que.push(EDGE(i,x,dist[x],-1));		//id=-1表示 不需要用到id
				}
			}  
					
			 
		} 
		//  求最小权值和
		 __int64 sum=0;
		for (i=1;i<=n;i++)
		{
			if (i==st) continue;
			__int64 MIN=INF;
			int min_EDGE_id;
			for (j=0;j<tm[i].size();j++)
			{
				__int64 y=tm[i][j].x; 
				if (y==i) continue;
				__int64 v=tm[i][j].v;
				if (dist[i]==dist[y]+v&&v<MIN)
				{
					MIN=v;
					min_EDGE_id=tm[i][j].id;
				}
			}
			sum+=MIN;
			ans.push_back(min_EDGE_id);

		} 
		printf("%I64d\n",sum);
		for (i=0;i<ans.size();i++)
		{ 
			if (i!=0) printf(" ");
			printf("%d",ans[i]);
		}
		printf("\n");
		return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值