2018年ACM俱乐部个人训练赛第十六场 问题C.道路重建

问题 C: 道路重建

时间限制: 1 Sec  内存限制: 128 MB

题目描述

小L的家乡最近遭遇了一场洪水,城市变得面目全非,道路也都被冲毁了。生活还要继续,于是市政府决定重建城市中的道路。
在洪水到来前,城市中共有n个区域和m条连接这些区域的双向道路, 道路连通了所有的区域,为了方便人们的出行,只能重建这些原有的道路, 不能建新的道路。编号为s的区域是市政广场,市政府希望重建的道路能够 使得所有区域到市政广场的最短路与受灾前保持不变,同时为了节约救灾 经费,还要使得修建的所有道路的长度和尽可能小。
小L为了拯救心爱的家乡,决定站出来,成为优秀的青年理论计算机科 学家,于是马上投入到了对这个问题的研究中。你能帮帮小L吗?

输入

第一行两个整数n和m,表示区域与道路的个数。
接下来m行,每行三个正整数u,v和w,描述一条连接u和v、长为w的道路。
最后一行,一个正整数s,表示市政广场的编号。

输出

输出一个整数,表示最小长度和。

样例输入

5 7

1 2 1

2 3 4

2 4 2

4 3 2

5 2 2

4 5 1

5 1 1

2

样例输出

6

提示

最优方案是重建1-2,1-5,2-4,4-3的道路,此时所有区域到达区域2的最短路分别是1, 0, 4, 2, 2,道路长度和是1 + 1 + 2 + 2 = 6。
对于20%的数据,n ≤ 10, m ≤ 20;
对于另外30%的数据,边权不超过2;
对于100%的数据,1 ≤ n ≤ 105, n − 1 ≤ m ≤ 2 ∗ 105, 1 ≤ w ≤ 109






分析:

最后形成的是一棵树  除s点外每点的入度都为1  先跑一边最短路求出s到每点的最短路  然后维护最短路相同时入度中最短的边








AC代码:

#include <bits/stdc++.h>
#define mset(a,x) memset(a,x,sizeof(a))
const int INF=0x3f3f3f3f;
typedef long long ll;
using namespace std;
int cnt;
int n,m,s;
ll dis[2000005];
ll res[2000005];
int vis[2000005];
int head[2000005];
struct Edge{
    int next;
    int to;
    ll w;
}edge[4000005];
void add(int u,int v,ll w){
    edge[cnt].w=w;
    edge[cnt].to=v;
    edge[cnt].next=head[u];
    head[u]=cnt++;
}
void spfa(int flag){
    mset(vis,0);
    queue<int> Q;
    Q.push(s);
    vis[s]=1;
    dis[s]=0;
    res[s]=0;
    while (!Q.empty()){
        int u=Q.front();
        Q.pop();
        vis[u]=0;
        for (int i=head[u];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(dis[v]>dis[u]+edge[i].w&&!flag){
                dis[v]=dis[u]+edge[i].w;
                if (!vis[v]){
                    vis[v]=1;
                    Q.push(v);
                }
            }
            if(dis[v]==dis[u]+edge[i].w&&flag){
                if(res[v]>edge[i].w) res[v]=edge[i].w;
                if (!vis[v]){
                    vis[v]=1;
                    Q.push(v);
                }
            }
        }
    }
}
void init(){
     cnt=0;
     memset(head,-1,sizeof(head));
}
int main (){
    while (scanf ("%d%d",&n,&m)!=EOF){
        int u,v;
        ll w;
        init();
        for (int i=0;i<m;i++){
            scanf("%d%d%lld",&u,&v,&w);
            add(u,v,w);add(v,u,w);
        }
        scanf ("%d",&s);
        mset(dis,INF);spfa(0);
        mset(res,INF);spfa(1);
        ll sum=0;
        for (int i=1;i<=n;i++) sum+=res[i];
        printf ("%lld\n",sum);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/mm__1997/article/details/79428101