问题 C: 道路重建
时间限制: 1 Sec 内存限制: 128 MB
提交: 67 解决: 24
[提交][状态][讨论版]
题目描述
小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。
题解:spfa 外加一个pre[]数组用来存该点到上一个点的距离
代码如下:
#include<iostream> #include<cstring> #include<queue> #include<cstdio> #include<map> #define ll long long using namespace std; const int inf=1e9+7; const int maxn=1e6+5; struct Edge{ int to,next,w; }edge[maxn]; int head[maxn],vis[maxn],pre[maxn],cnt,n,m; ll dis[maxn]; void add(int u,int v,int w) { edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].w=w; head[u]=cnt++; } void spfa(int s) { ll ans=0; queue <int> q; for(int i=1;i<=n;i++) dis[i]=1e18; memset(vis,0,sizeof(vis)); q.push(s); dis[s]=0; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=false; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to,w=edge[i].w; if(dis[v]>=dis[u]+w) { if(dis[v]>dis[u]+w) { ans+=w; if(dis[v]!=1e18) ans-=pre[v]; pre[v]=w; } else { if(pre[v]>w) { ans+=w-pre[v]; pre[v]=w; } } dis[v]=dis[u]+w; if(!vis[v]) { vis[v]=true; q.push(v); } } } } printf("%lld\n",ans); } int main() { int st; scanf("%d%d",&n,&m); int u,v,w; for(int i=0;i<=n;i++) head[i]=-1; cnt=0; for(int i=0;i<m;i++) { scanf("%d%d%d",&u,&v,&w); add(u,v,w); add(v,u,w); } scanf("%d",&st); spfa(st); return 0; }
原文地址:https://www.cnblogs.com/lemon-jade/p/8496731.html
时间: 2024-10-15 10:56:58