匈牙利游戏(次短路问题)
匈牙利游戏
来源: 2012年CCC加拿大高中生信息学奥赛
题目描述:
欢迎来到匈牙利游戏!布达佩斯(匈牙利首都)的街道形成了一个弯曲的单向网络。
你被强制要求参加一个赛跑作为一个TV秀的一部分节目,比赛中你需要穿越这些街道,从s开始,到t结束。
很自然的,你想要尽快的完成比赛,因为你的比赛完成的越好,你就能得到更多的商业促销合同。
但是,有一个需要了解的是,如果有人过于聪明找到从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)对。
输出描述 Output Description
输出从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、如果from的最短路能更新to的最短路,就让更新之前的最短路等于次短路,然后去更新最短路。
2、如果from的最短路不能跟新to的最短路,但是可以更新次短路,就去更新次短路。
3、如果form的最短路不能跟新to的最短路,也不能更新次短路,但是from的次短路可以更新to的次短路,那么就去更新次短路。
#include<iostream>
#include<queue>
using namespace std;
const int maxn=20010;
struct node
{
int to;
int w;
int next;
}e[maxn*50];
queue<int> q;
bool in[maxn];
int n,m,tot,head[maxn];
long long dis[maxn],sdis[maxn];
void edd_edge(int u,int v,int w)
{
tot++;
e[tot].to=v;
e[tot].w=w;
e[tot].next=head[u];
head[u]=tot;
}
void spfa(int s)
{
dis[s]=0;
in[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
in[u]=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[u]+e[i].w)
{
sdis[v]=dis[v];
dis[v]=dis[u]+e[i].w;
if(!in[v])
{
q.push(v);
in[v]=1;
}
}
else if(dis[v]!=dis[u]+e[i].w&&sdis[v]>dis[u]+e[i].w)
{
sdis[v]=dis[u]+e[i].w;
if(!in[v])
{
q.push(v);
in[v]=1;
}
}
if(sdis[v]>sdis[u]+e[i].w)
{
sdis[v]=sdis[u]+e[i].w;
if(!in[v])
{
q.push(v);
in[v]=1;
}
}
}
}
}
int main()
{
int x,y,z;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>x>>y>>z;
edd_edge(x,y,z);
}
for(int i=1;i<=n;i++)
dis[i]=sdis[i]=maxn*50000;
spfa(1);
if(sdis[n]<maxn*50000)
cout<<sdis[n];
else
cout<<-1;
return 0;
}