1726: [Usaco2006 Nov]Roadblocks第二短路
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1578 Solved: 795
[Submit][Status][Discuss]
Description
贝茜把家搬到了一个小农场,但她常常回到FJ的农场去拜访她的朋友。贝茜很喜欢路边的风景,不想那么快地结束她的旅途,于是她每次回农场,都会选择第二短的路径,而不象我们所习惯的那样,选择最短路。 贝茜所在的乡村有R(1<=R<=100,000)条双向道路,每条路都联结了所有的N(1<=N<=5000)个农场中的某两个。贝茜居住在农场1,她的朋友们居住在农场N(即贝茜每次旅行的目的地)。 贝茜选择的第二短的路径中,可以包含任何一条在最短路中出现的道路,并且,一条路可以重复走多次。当然咯,第二短路的长度必须严格大于最短路(可能有多条)的长度,但它的长度必须不大于所有除最短路外的路径的长度。
Input
* 第1行: 两个整数,N和R,用空格隔开
* 第2..R+1行: 每行包含三个用空格隔开的整数A、B和D,表示存在一条长度为 D(1 <= D <= 5000)的路连接农场A和农场B
Output
* 第1行: 输出一个整数,即从农场1到农场N的第二短路的长度
Sample Input
1 2 100
2 4 200
2 3 250
3 4 100
Sample Output
输出说明:
最短路:1 -> 2 -> 4 (长度为100+200=300)
第二短路:1 -> 2 -> 3 -> 4 (长度为100+250+100=450)
HINT
Source
题意:
求无向图中$1 ightarrow N$的严格次短路长度。
题解:
树上次长链都会维护了,图上次短路怎么能不会……
考虑常用的$Dijkstra$的运行过程,每次从优先队列队首挑一个$dis$最小的点,该点的$dis$就被确定下来(都是正权边一定没有再能更新他的边)。
然后通过该点松弛与之相连的其他点并把它们扔到优先队列中。扔到$N$即可退出。
那么次短路同理,在优先队列中出现的第一个不等于该点最短路的次短路一定是唯一确定的(没有再能更新他的最短路或次短路)。
于是只需要记录该点最短路和次短路是否出现过,并在往优先队列里push的时候标记上这是最短路还是次短路即可。
注意最短路若被更新,次短路要继承最短路的值。
代码:(md我优先队列排序排反还在bzoj上$A$了是什么操作啊)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define MAXN 100005 #define MAXM 500005 #define INF 0x7fffffff #define ll long long struct node{ int u,d,c; bool operator<(const node b)const{ return d>b.d; } }; int hd[MAXN],to[MAXM<<1]; int nxt[MAXM<<1],cst[MAXM<<1]; int N,M,cnt,dis[MAXN][2]; bool vis[MAXN][2]; inline int read(){ int x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void addedge(int u,int v,int w){ to[++cnt]=v,cst[cnt]=w; nxt[cnt]=hd[u],hd[u]=cnt; return; } inline int Dijkstra(int s){ memset(dis,63,sizeof(dis)); memset(vis,0,sizeof(vis)); priority_queue<node> q; q.push({1,0,0}); dis[1][0]=0; while(!q.empty()){ node h=q.top();q.pop(); if(vis[h.u][h.c]) continue; vis[h.u][h.c]=1; for(int i=hd[h.u];i;i=nxt[i]){ int u=h.u,v=to[i],w=cst[i]; if(dis[v][0]>h.d+w){ dis[v][1]=dis[v][0]; dis[v][0]=h.d+w; q.push(node{v,dis[v][0],0}); q.push(node{v,dis[v][1],1}); } if(dis[v][1]>h.d+w && h.d+w!=dis[v][0]){ dis[v][1]=h.d+w; q.push(node{v,dis[v][1],1}); } } } return dis[N][1]; } int main(){ N=read(),M=read(); for(int i=1;i<=M;i++){ int u=read(),v=read(),w=read(); addedge(u,v,w);addedge(v,u,w); } printf("%d ",Dijkstra(1)); return 0; }