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 }
View Code

2017/7/13

原文地址:https://www.cnblogs.com/UnderSilenceee/p/7161512.html