Codeforces 545E. Paths and Trees[最短路+贪心]
[题目大意]
题目将从某点出发的所有最短路方案中,选择边权和最小的最短路方案,称为最短生成树。
题目要求一颗最短生成树,输出总边权和与选取边的编号。
[题意分析]
比如下面的数据:
5 5
1 2 2
2 3 2
3 4 16
1 5 18
4 5 2
1
这个图对于从 1 出发,有两种最短路。
这种最短路方案中 dis[2]=2,dis[3]=4,dis[4]=20,dis[5]=18。边权总和 Sum=44
但如果这样选边,1点到各点的距离依然为最短路,但Sum降为了24。
那么如何选择到最优的方案呢。 由于最短路方案构成的图一定是一棵树,所以我们可以将 除源点外 的所有顶点搞一个贪心。
改写dijkstra算法(c[]数组用来存取与该点连接的边的cost,s[]数组用来存取与该点连接的边的编号):
const ll inf=0x7fffffffffffff; struct Edge{ int to,cost,id; Edge(int T,int C,int D):to(T),cost(C),id(D){} }; typedef pair<long long,int> P; vector<Edge>G[300005]; ll d[300005],c[300005]; void dij(int u){ fill(d,d+n+1,inf); fill(c,c+n+1,inf); d[u]=0; priority_queue<P,vector<P>,greater<P>> q; q.push(P(d[u],u)); while(!q.empty()){ P p=q.top(); q.pop(); int v=p.second; if(d[v]<p.first) continue; for(int i=0;i<G[v].size();i++){ Edge e=G[v][i]; if(d[e.to]>d[v]+e.cost){ d[e.to]=d[v]+e.cost; s[e.to]=e.id; c[e.to]=e.cost; q.push(P(d[e.to],e.to)); } else if(d[e.to]==d[v]+e.cost&&c[e.to]>e.cost){ s[e.to]=e.id; c[e.to]=e.cost; } } } }
当有多条路通往一个顶点,且这两种路线cost相同时,我们可以将 通往该顶点的边 和 该顶点 绑定起来,我们希望每个顶点都能绑定合法的(不影响最短路的)且权值最小的边。
在dijkstra算法中我们每次挑选优先队列中权值最小的路。当碰上两条路cost相等的时候,我们选择与下一个点连接且边权最小的那一条边与下一个点绑定(Cost[nextV]=e.cost)。
* 由于最短路中从源点通往每个点的路可以组成一颗树 且 点只与从源点走向该点的边相绑定,所以一个点 一定可以 绑定一条边。
选取完毕后,我们只需要遍历 c[] 数组求出总花费,再遍历 s[] 数组输出每个点绑定的边的编号即可。
***Code:
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 int m,n,s[300005]; 5 const ll inf=0x7fffffffffffff; 6 struct Edge{ 7 int to,cost,id; 8 Edge(int T,int C,int D):to(T),cost(C),id(D){} 9 }; 10 typedef pair<long long,int> P; 11 vector<Edge>G[300005]; 12 ll d[300005],c[300005]; 13 void dij(int u){ 14 fill(d,d+n+1,inf); 15 fill(c,c+n+1,inf); 16 d[u]=0; 17 priority_queue<P,vector<P>,greater<P>> q; 18 q.push(P(d[u],u)); 19 while(!q.empty()){ 20 P p=q.top(); 21 q.pop(); 22 int v=p.second; 23 if(d[v]<p.first) continue; 24 for(int i=0;i<G[v].size();i++){ 25 Edge e=G[v][i]; 26 if(d[e.to]>d[v]+e.cost){ 27 d[e.to]=d[v]+e.cost; 28 s[e.to]=e.id; 29 c[e.to]=e.cost; 30 q.push(P(d[e.to],e.to)); 31 } 32 else if(d[e.to]==d[v]+e.cost&&c[e.to]>e.cost){ 33 s[e.to]=e.id; 34 c[e.to]=e.cost; 35 } 36 } 37 } 38 } 39 int main(){ 40 int u,v,co; 41 scanf("%d%d",&n,&m); 42 for(int i=1;i<=m;i++){ 43 scanf("%d%d%d",&u,&v,&co); 44 G[u].push_back(Edge(v,co,i)); 45 G[v].push_back(Edge(u,co,i)); 46 } 47 scanf("%d",&u); 48 dij(u); 49 ll sum=0; 50 for(int i=1;i<=n;i++){ 51 if(i!=u) sum+=c[i]; 52 } 53 cout<<sum<<endl; 54 for(int i=1;i<=n;i++){ 55 if(i!=u) cout<<s[i]<<' '; 56 } 57 return 0; 58 }
2017/7/13