匈牙利游戏
【题目描述】
布达佩斯的街道形成了一个弯曲的单向网络。你要参加一个赛跑,比赛中你需要穿越这些街道,从s开始,到t结束。
要求写一个程序来计算一个从s到t的严格次短路线。
严格次短路线可能访问某些节点不止一次,样例2是一个例子。
【输入描述】
第一行包含两个整数N和M,N代表布达佩斯的节点个数,M代表边的个数。节点编号从1到N。1代表出发点s,N代表终点t;
接下来的M行每行三个整数A、B、L,代表有一条从A到B的长度为L的单向同路。你可以认为A不等于B,也不会有重复的(A,B)对。
【输出描述】
输出从s到t的严格次短路的长度。如果从s到t的路少于2条,输出-1。
【样例输入】
样例1:
4 6
1 2 5
1 3 5
2 3 1
2 4 5
3 4 5
1 4 13
样例2:
2 2
1 2 1
2 1 1
【样例输出】
样例1:
11
样例2:
3
【数据范围及提示】
样例1:
有两条长度为10的最短路径(1 → 2 → 4,1 → 3 → 4)并且有一条长度为11的严格次短路径(1 → 2 → 3 → 4)。
样例2:
有一条长度为1的最短路径(1 → 2)并且有一条长度为3的严格次短路径(1 → 2 → 1 → 2)。
源代码: #include<cstdio> #include<cstring> #include<queue> using namespace std; struct Node { int Next,To,T; }i[1000001]; queue <int> Q; bool in[200001]={0}; int n,m,Num(0),Head[200001]; long long dis[200001],f[200001]; //RE真乃神坑也! void Add(int A,int B,int C) { i[++Num].To=B; i[Num].T=C; i[Num].Next=Head[A]; Head[A]=Num; } void SPFA(int S) { dis[S]=0; in[S]=true; Q.push(S); while (!Q.empty()) { int t1=Q.front(); Q.pop(); in[t1]=false; for (int a=Head[t1];a;a=i[a].Next) { int t2=i[a].To; if (dis[t2]>dis[t1]+i[a].T) { f[t2]=dis[t2]; //次短路更新。 dis[t2]=dis[t1]+i[a].T; //最短路更新。 if (!in[t2]) { Q.push(t2); //入队是因为图有了变化,是否能引起连锁反应。 in[t2]=true; } } else if (dis[t2]!=dis[t1]+i[a].T&&f[t2]>dis[t1]+i[a].T) //只更新次短路。 { f[t2]=dis[t1]+i[a].T; if (!in[t2]) { Q.push(t2); in[t2]=true; } } else if (f[t2]>f[t1]+i[a].T) //仔细想一想会发现,当dis[t2]=dis[t1]时,只得如此更新。 { f[t2]=f[t1]+i[a].T; if (!in[t2]) { Q.push(t2); in[t2]=true; } } } } } int main() { scanf("%d%d",&n,&m); for (int a=1;a<=m;a++) { int A,B,C; scanf("%d%d%d",&A,&B,&C); Add(A,B,C); //有向边表。 } for (int a=1;a<=m;a++) //赋极大大大值。 dis[a]=f[a]=1000000000; SPFA(1); //从起点开始。 if (f[n]<1000000000) printf("%lld",f[n]); else printf("-1"); return 0; }