【SPFA】【最短路/次短路】GF打Dota

版权声明:欢迎借鉴,谢绝抄搬。 https://blog.csdn.net/ssllyf/article/details/88076411

GF打Dota

题目大意:

求一个点到另一个点的最短路或次短路

原题:

题目描述

众所周知,GF同学喜欢打dota,而且打得非常好。今天GF和Spartan同学进行了一场大战。现在GF拿到一张地图,地图上一共有n个地点,GF的英雄处于1号点,Spartan的基地位于n号点,GF要尽快地选择较短的路线让他的英雄去虐掉Spartan的基地。但是Spartan早就料到了这一点,他有可能会开挂(BS~)使用一种特别的魔法,一旦GF所走的路线的总长度等于最短路的总长度时,GF的英雄就要和这种魔法纠缠不休。这时GF就不得不选择非最短的路线。现在请你替GF进行规划。
对于描述的解释与提醒:
1.无向路径,花费时间当然为非负值。
2.对于本题中非最短路线的定义:不管采取任何迂回、改道方式,只要GF所走的路线总长度不等于1到n最短路的总长度时,就算做一条非最短的路线。
3.保证1~n有路可走。

输入

第一行为n,m(表示一共有m条路径)
接下来m行,每行3个整数a,b,c,表示编号为a,b的点之间连着一条花费时间为c的无向路径。
接下来一行有一个整数p,p=0表示Spartan没有开挂使用这种魔法,p=1则表示使用了。

输出

所花费的最短时间t,数据保证一定可以到达n。

输入样例

样例输入1:

5 5
1 2 1
1 3 2
3 5 2
2 4 3
4 5 1
0

样例输入2:

5 5
1 2 1
1 3 2
3 5 2
2 4 3
4 5 1
1

输出样例

样例输出1:

4

样例输出2:

5

说明

对于50%的数据,1<=n,m<=5000
对于70%的数据,1<=n<=10000, 1<=m<=50000,p=0,
对于100%的数据,1<=n<=10000, 1<=m<=50000,p=1
无向图,花费时间c>=0

解题思路:

正着跑一遍SPFA,是第一个点到每一个点的最短路(a),倒着跑一遍SPFA,是每个点到n的最短路(b),如果是最短路就直接输出,如果是次短路,就枚举每一条边,将其中一个点的a和另一个点的b再加上这条边的长度,求出这条路线的长度,在这些中找出次短路即可

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
int n,m,x,y,c,w,pp,now,ans,sum,aa[50005],bb[50005],cc[50005],b[10005],b1[10005],p[10005],head[10005];
struct rec
{
	int to,next,l;
}a[100005];
int main()
{
	scanf("%d %d",&n,&m);
	for (int i=1;i<=m;++i)
	  {
	  	scanf("%d %d %d",&x,&y,&c);
	  	aa[i]=x;//记录线
	  	bb[i]=y;
	  	cc[i]=c;
	  	a[++w].to=y;//邻接表
	  	a[w].l=c;
	  	a[w].next=head[x];
	  	head[x]=w;
	  	a[++w].to=x;//双向
	  	a[w].l=c;
	  	a[w].next=head[y];
	  	head[y]=w;
	  }
	scanf("%d",&pp);
	memset(b,127/3,sizeof(b));
	memset(b1,127/3,sizeof(b1));
	queue<int>d;
	d.push(1);
	b[1]=0;
	p[1]=1;
	while(!d.empty())//正着
	{
		now=d.front();
		d.pop();
		for (int i=head[now];i;i=a[i].next)
		  if (b[now]+a[i].l<b[a[i].to])
		    {
		    	b[a[i].to]=b[now]+a[i].l;
		    	if (!p[a[i].to])
		    	  {
		    	  	p[a[i].to]=1;
		    	  	d.push(a[i].to);
		    	  }
		    }
		p[now]=0;
	}
	if (!pp)
	{
		printf("%d",b[n]);
		return 0;
	}
	sum=b[n];
	d.push(n);
	b1[n]=0;
	p[n]=1;
	while(!d.empty())//倒着
	{
		now=d.front();
		d.pop();
		for (int i=head[now];i;i=a[i].next)
		  if (b1[now]+a[i].l<b1[a[i].to])
		    {
		    	b1[a[i].to]=b1[now]+a[i].l;
		    	if (!p[a[i].to])
		    	  {
		    	  	p[a[i].to]=1;
		    	  	d.push(a[i].to);
		    	  }
		    }
		p[now]=0;
	}
	ans=2147483647;
	for (int i=1;i<=m;++i)
	  {
	  	if (b[aa[i]]+b1[bb[i]]+cc[i]>sum)//连接线
	  	  ans=min(ans,b[aa[i]]+b1[bb[i]]+cc[i]);
	  	if (b[bb[i]]+b1[aa[i]]+cc[i]>sum)//反过来
	  	  ans=min(ans,b[bb[i]]+b1[aa[i]]+cc[i]);
	  }
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/ssllyf/article/details/88076411