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

  • 相关阅读:
    Leetcode [654] 最大二叉树 &[105] 从前序与中序遍历序列构造二叉树 & [106] 从中序与后序遍历序列构造二叉树
    Leetcode [226] 翻转二叉树 & [116] 填充每个节点的下一个右侧节点指针 & [114] 二叉树展开为链表
    Leetcode 链表&二叉树刷题总结
    Leetcode 动态规划刷题总结
    Leetcode [1312] 让字符串成为回文串的最少插入次数 动态规划
    Leetcode [234] 回文链表 回文 链表
    动态规划之 KMP 算法详解(转)
    Leetcode [99] 恢复二叉搜索树 二叉树
    统计代码行数
    二叉树遍历(递归、非递归、mirror)转
  • 原文地址:https://www.cnblogs.com/UnderSilenceee/p/7161512.html
Copyright © 2011-2022 走看看