luogu P2829 大逃离
题目背景
zrz走进了一个奇葩的迷宫,他发现自己迷路了,想逃出来,他好不容易数完了所有的路,累的快晕了,只好叫你帮忙咯。
题目描述
这是一棵有n个节点的图,有m条双向边,每一条路有w个单位距离,zrz在1的位置,出口在n的位置,不过zrz脑子出了点bug,于是不想走最短的路,想走第2短的路,第2短路径允许与最短路径有重边,然后也可以重复通过一些节点和路,注意如果有多条路径都是最短路径,那么他们都不能叫第2短路径。但是zrz觉得如果接下来进入的一个节点所直接连接的地方小于k个(起点和终点除外),那么他就不敢进去。
输入输出格式
输入格式:
第一行3个数:n,m,k
接下来m行:每行3个数,u,v,w。表示从u到v有一条权值为w的边。(u,v<=n,w<=10000)
输出格式:
一个数:表示从s走到t的第2短路的值,如果不存在,输出-1
输入输出样例
说明
对于50%的数据:n<=10,m<=10
对于90%的数据:n<=1000,m<=20000
对于100%的数据:n<=5000,m<=100000
另外,k比较小
样例2最短路径是300(1-2-4)。因为从2无法走到3(3连接到的节点只有2个),所以可以1-2-1-2-4,第二短路为500。
题目链接:https://www.luogu.org/problemnew/show/2829
解题报告:
SPFA求次短路,松弛操作.
AC代码
#include<cstdio> #include<iostream> #include<cmath> #include<queue> #define INF (1<<30) #define ll long long #define BIG 200011 using namespace std; queue<int>q; int x,y,z,tot,cnt; int n,m,k,d1[BIG],d2[BIG],inq[BIG]; int nxt[BIG],las[BIG],to[BIG],w[BIG],deg[BIG]; #define FOR(s,t) for(register int i=s;i<=t;++i) #define VIS(now) for(register int e=las[now];e;e=nxt[e]) inline void add(int x,int y,int z){ nxt[++tot]=las[x],las[x]=tot,to[tot]=y,w[tot]=z; } inline void SPFA(){ FOR(2,n)d1[i]=d2[i]=INF; d2[1]=INF; q.push(1); inq[1]=1; int u,v; while(!q.empty()){ u=q.front();q.pop(); inq[u]=0; VIS(u){ v=to[e]; if(v!=n&&v!=1°[v]<k)continue; if(d1[v]>=d1[u]+w[e]){ d2[v]=min(d2[v],d2[u]+w[e]),d1[v]=d1[u]+w[e]; if(!inq[v])q.push(v),inq[v]=1; } else if(d2[v]>d1[u]+w[e]){ d2[v]=d1[u]+w[e]; if(!inq[v])q.push(v),inq[v]=1; } } } } int main(){ scanf("%d%d%d",&n,&m,&k); while(m--){ scanf("%d%d%d",&x,&y,&z); add(y,x,z),add(x,y,z); } FOR(2,n-1){ VIS(i) if(!inq[to[e]])inq[to[e]]=1,++deg[i]; VIS(i) inq[to[e]]=0; } SPFA(); printf("%d\n",d2[n]<INF?d2[n]:(-1)); return 0; }