#10076.「一本通 3.2 练习 2」Roadblocks:https://loj.ac/problem/10076
解法:
次短路具有一种性质:次短路一定是由起点到点x的最短路 + x到y的距离 + y到终点的最短路构成,且次短路的权值和严格大于最短路的权值和。
我们可以从起点跑一次Dijkstra,再从终点跑一次Dijkstra,这样起点到每个点的最短距离以及终点到每个点的最短距离都已经确定了,
接着枚举每一个节点u,再枚举从该点从发的每一条边v,更新答案就可以了。
最后由于题目中的边可以重复走,所以把(u,v)的边权*3倍也计算进去就可以了。
#include<bits/stdc++.h> using namespace std; #define re register int #define ll long long #define INF 0x3f3f3f3f #define maxn 5009 #define maxm 100009 inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ll)(ch-'0');ch=getchar();} return x*f; } int head[maxn],dis[maxn],dist[maxn]; //dist 1->n的最短路 dis n->1的最短路 bool vis[maxn]; struct edge { int to,nxt,val; }p[maxm<<1]; int n,m,k,ans,tot,cnt,mx,sum; void add(int x,int y,int z) { ++cnt,p[cnt].to=y,p[cnt].nxt=head[x],p[cnt].val=z,head[x]=cnt; } void Dijkstra(int x) { memset(dis,INF,sizeof(dis)); memset(vis,0,sizeof(vis)); priority_queue<pair<int,int> >q; dis[x]=0; q.push(make_pair(0,x)); while(q.size()) { int u=q.top().second;q.pop(); if(vis[u]) continue; vis[u]=1; for(int i=head[u];i;i=p[i].nxt) { int v=p[i].to; if(dis[v]>dis[u]+p[i].val) { dis[v]=dis[u]+p[i].val; q.push(make_pair(-dis[v],v)); } } } } int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); n=read(),m=read(); for(int i=1;i<=m;i++) { int x=read(),y=read(),z=read(); add(x,y,z),add(y,x,z); } Dijkstra(1); for(int i=1;i<=n;i++) dist[i]=dis[i]; Dijkstra(n); /* for(int i=1;i<=n;i++) cout<<dist[i]<<" "; cout<<endl; for(int i=1;i<=n;i++) cout<<dis[i]<<" "; cout<<endl;*/ ans=INF; for(int u=1;u<=n;u++) { for(int i=head[u];i;i=p[i].nxt) { int v=p[i].to; int diss=dist[u]+p[i].val+dis[v]; if(diss<ans&&diss>dist[n]) ans=diss; diss+=p[i].val*2; if(diss<ans&&diss>dist[n]) ans=diss; } } printf("%d ",ans); fclose(stdin); fclose(stdout); return 0; }