Wormholes POJ 3259(spfa判断负环)

WormholesPOJ - 3259

耳机楼里有很多教室,这些教室由双向走廊连接。另外,还存在一些单向的秘密通道,通过它们可以回到过去。现在有 N (1 ≤ N ≤ 500) 个教室,编号 1..N, M (1 ≤ M ≤ 2500) 条走廊,和 W (1 ≤ W ≤ 200) 条秘密通道。

DY在养猫之余,还是一个时间旅行爱好者。她希望从一间教室出发,经过一些走廊和秘密通道,回到她出发之前的某个时间。

共有F (1 ≤ F ≤ 5) 组数据。对每组数据,判断DY是否有回到过去的可能性。不存在耗时超过10,000秒的走廊,且不存在能带DY回到10,000秒之前的秘密通道。

Input

首先是一个整数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秒。

OutputF行,每行对应一组数据。每组数据输出单独的一行,” YES”表示能满足要求,”NO”表示不能满足要求。Sample Input
2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8
Sample Output
NO
YES

分析:

涉及环的问题,考虑求负环,这里尝试用spfa(队列优化的BF)做的,只要有点进入队列超过n-1次就存在负环,结果因为图没更新,WA了两次。。。变量一多就容易漏啊。。。

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<stack>   
#include<set>  
#include<bitset>  
#include<list>

#define UP(i,x,y) for(int i=x;i<=y;i++)  
#define DOWN(i,x,y) for(int i=x;i>=y;i--)  
#define MEM(a,x) memset(a,x,sizeof(a))
#define W(a) while(a) 
#define ll long long  
#define INF 0x3f3f3f3f  
#define EXP 1e-10  
#define lowbit(x) (x&-x)
 
using namespace std;
int n,m,w;
struct edge{
	int to,cost;
	edge(int to,int cost):to(to),cost(cost){}
};
vector<edge> G[1510];
int dis[1510],is_join[1510],join_num[1510];
queue<int> q;
bool BF(void){
	MEM(dis,0x3f);
	MEM(is_join,0);
	MEM(join_num,0);
	while(!q.empty())q.pop();
	q.push(1);
	dis[1]=0;
	is_join[1]=1;
	join_num[1]++;
	while(!q.empty()){
		int head=q.front();
		q.pop();
		is_join[head]=0;
		for(int i=0;i<G[head].size();i++){
			int t=G[head][i].to,c=G[head][i].cost;
			if(dis[t]>dis[head]+c){
				dis[t]=dis[head]+c;
				if(is_join[t]==0){
					q.push(t);
					is_join[t]=1;
					join_num[t]++;
					if(join_num[t]>=n)return 1;
				}
			}
		}
		/*for(int i=1;i<=n;i++){
			cout<<dis[i]<<' ';
		}
		cout<<endl;*/
	}
	return 0; 
}
int main(){
	int f;cin>>f;
	while(f--){
		cin>>n>>m>>w;
		for(int i=1;i<=m;i++){
			int s,e,t;
			cin>>s>>e>>t;
			edge ed1(e,t),ed2(s,t);
			G[s].push_back(ed1);
			G[e].push_back(ed2);
		}
		for(int i=1;i<=w;i++){
			int s,e,t;
			cin>>s>>e>>t;
			edge ed(e,t*(-1));
			G[s].push_back(ed);
		}
		if(BF()) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
		for(int i=1;i<=n;i++){
			G[i].clear();
		}
	}
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值