zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    在預設設定下,SQL Server 不允許遠端連接
    windows7语言包安装失败
    使一个销售组织能够销售另一个销售组织的产品
    转:多线程六种多线程方法解决UI线程阻塞
    转:BeginInvoke和EndInvoke方法 (原网址:http://www.cnblogs.com/nokiaguy/archive/2008/07/13/1241817.html)
    员工客户的统驭科目不能更改?
    公司间采购的退货(有序列号)
    排程 经典图示
    取消凭证分解 (取消公司下的多个利润中心)
    查找已删除的交货单信息
  • 原文地址:https://www.cnblogs.com/UnderSilenceee/p/7161512.html
Copyright © 2011-2022 走看看