问题 C: 道路重建
时间限制: 1 Sec 内存限制: 128 MB题目描述
小L的家乡最近遭遇了一场洪水,城市变得面目全非,道路也都被冲毁了。生活还要继续,于是市政府决定重建城市中的道路。
在洪水到来前,城市中共有n个区域和m条连接这些区域的双向道路, 道路连通了所有的区域,为了方便人们的出行,只能重建这些原有的道路, 不能建新的道路。编号为s的区域是市政广场,市政府希望重建的道路能够 使得所有区域到市政广场的最短路与受灾前保持不变,同时为了节约救灾 经费,还要使得修建的所有道路的长度和尽可能小。
小L为了拯救心爱的家乡,决定站出来,成为优秀的青年理论计算机科 学家,于是马上投入到了对这个问题的研究中。你能帮帮小L吗?
在洪水到来前,城市中共有n个区域和m条连接这些区域的双向道路, 道路连通了所有的区域,为了方便人们的出行,只能重建这些原有的道路, 不能建新的道路。编号为s的区域是市政广场,市政府希望重建的道路能够 使得所有区域到市政广场的最短路与受灾前保持不变,同时为了节约救灾 经费,还要使得修建的所有道路的长度和尽可能小。
小L为了拯救心爱的家乡,决定站出来,成为优秀的青年理论计算机科 学家,于是马上投入到了对这个问题的研究中。你能帮帮小L吗?
输入
第一行两个整数n和m,表示区域与道路的个数。
接下来m行,每行三个正整数u,v和w,描述一条连接u和v、长为w的道路。
最后一行,一个正整数s,表示市政广场的编号。
接下来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;
}