Codeforces#303-E-Paths and Treesg-最短回路+最小生成ツリー

2639 ワード

http://codeforces.com/contest/545/problem/E
題意:無方向図G、始点Uを与えて、1つのサブ図を探し当てることを求めて、【サブ図の中でUから各点までの最短ルートは原図と等しい】、求める 【すべてのエッジ権の和が最小】サブマップ
出力ウェイト値と+各エッジの番号(エッジは入力順に1からmまで)
構想:直接最短ルートを求めてdist[]配列を得る
そして
 for (i=1;i<=n; i++)
{
//点iに接続されているすべてのエッジを巡り、エッジが1つ見つかれば 【始点から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
",sum); for (i=0;i<ans.size();i++) { if (i!=0) printf(" "); printf("%d",ans[i]); } printf("
"); return 0; }