Wormholes

题目链接

在探索他的许多农场时,农夫约翰发现了许多令人惊奇的虫洞。虫洞是非常特殊的,因为它是一条单行道,在你进入虫洞之前把你送到目的地!FJ的每一个农场都包括N(1≤N≤500)个区域,方便编号为1…N、 M(1≤M≤2500)条路径W(1≤W≤200)个虫洞。 因为FJ是一个狂热的时间旅行迷,他想做以下的事情:从某个领域开始,穿过一些路径和虫洞,在他最初离开之前的一段时间回到起始领域。也许他能认识自己:)。
为了帮助FJ了解这是否可行,他将向您提供其农场F(1≤F≤5)的完整地图。任何路径的运行时间都不会超过10000秒,任何虫洞都不能使FJ及时返回10000秒以上
输入
第1行:一个整数,F.F农场描述如下。
每个农场的第1行:三个空间分隔的整数:n、m和w
第2行…每个农场的M+1:三个空格分隔的数字(S、E、T),分别表示:S和E之间的双向路径,需要T秒才能穿过。两个字段可以通过多个路径连接。
线M+2…每个农场的M+W+1:分别描述三个空格分隔的数字(S、E、T):从S到E的单向路径,也将旅行者向后移动T秒
输出
第1行…F:对于每一个农场,如果FJ能够实现他的目标,输出“是”,否则输出“否”(不包括报价)。

记住两个重要的词组:
1,
a bidirectional path between S and E.
S和E之间的一条双向路径
2,从S到E的一条单向路径
A one way path from S to E

题目大意:有两中普通的路径,一种是双向路径,一种是单向路径(也就是虫洞),虫洞会让你从S到E地,但是所用的时间是
-T,普通的路径就很普通了。

其实这个题是一个判断负环的例题啊。
你想a<–>b<–>c<–>d~~>a,前三条是普通路径,后面d到a是虫洞,消耗的时间是负数,如果存在一个负环(比如,a-》b ,1秒,b-》c,1秒,c->d,1秒,d到a,-4秒,跑一圈后,a回到a所用时间-1秒,就叫存在负环),那么就可以满足题目要求,所以题目就变成了用Bellman—ford,去判断是否存在负环啊哈c上有介绍,但是是基于有向边)

//基于bellman——ford处理负环
//同时处理无向边和有向边
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
	int u,v,t;
}e[3000];
int dis[3000];
const int inf=0x3f3f3f3f;
int main()
{
	int f,n,m,w;
	scanf("%d",&f);
	
	int i,j,k;
	while(f--)
	{
		scanf("%d%d%d",&n,&m,&w);
		//输入无向边,虽然是无向边,但是只存储一条,具体看后面的操作
		for(i=1;i<=m;i++)
		{
			scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].t);
		}
		//存储虫洞的信息,时间去负
		for(i=1,j=m+1;i<=w;i++,j++)
		{
			scanf("%d%d%d",&e[j].u,&e[j].v,&e[j].t);
			e[j].t=-e[j].t;
		}
		
		for(i=1;i<=n;i++)
		dis[i]=inf;
		dis[1]=0;
		k=0;
		
		//第一层循环,松弛n次
		//说一下为什么要松弛n次,
		//先想为什么松弛n-1次,
		//松弛n-1次之后,相当于形成了一条长度为n-1的路径,
		//松弛第n次,判断这个形成的路径,会不会有点的信息被更新,如果还有就说明有了
		//(以上大佬给讲的,挺有道理)
		for(i=1;i<=n;i++)
		{
			k=0;
			for(j=1;j<=m+w;j++)
			{
				//无向图和有向图都要更新
				if(dis[e[j].v] > dis[e[j].u] + e[j].t)
				{
					k=1;
					dis[e[j].v] = dis[e[j].u] + e[j].t;
				}
				//无向图更新,有向就不用了。
				if(j<=m&&dis[e[j].u] > dis[e[j].v] + e[j].t)
				{
					k=1;
					dis[e[j].u] = dis[e[j].v] + e[j].t;
				}
			}
		}
		//如果再上面的最后一次(更新n-1次)之后,没有点的信息,被修改,说明没有负环,
		//此时k==0,输出NO;如果k==1,说明在第n次时更新了点的信息,说明存在负环。输出YES
		printf(k==1? "YES\n" : "NO\n");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值