1507:虫洞 Wormholes

【题目描述】
原题来自:USACO 2006 Dec. Gold,原文见 POJ 3259

John 在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。John 的每个农场有 M 条小路(无向边)连接着 N(从 1 到 N 标号)块地,并有 W 个虫洞。

现在 John 想借助这些虫洞来回到过去(在出发时刻之前回到出发点),请你告诉他能办到吗。 John 将向你提供 F 个农场的地图。没有小路会耗费你超过 104秒的时间,当然也没有虫洞回帮你回到超过 104 秒以前。

【输入】
第一行一个整数 F,表示农场个数;

对于每个农场:

第一行,三个整数 N,M,W;

接下来 M 行,每行三个数 S,E,T,表示在标号为 S 的地与标号为 E 的地中间有一条用时 T 秒的小路;

接下来 W 行,每行三个数 S,E,T,表示在标号为 S 的地与标号为 E 的地中间有一条可以使 John 到达 T 秒前的虫洞。

【输出】
输出共 F 行,如果 John 能在第 i 个农场实现他的目标,就在第 i 行输出 YES,否则输出 NO。

【输入样例】
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

【输出样例】
NO
YES

【提示】
数据范围:

对于全部数据,1≤F≤5,1≤N≤500,1≤M≤2500,1≤W≤200,1≤S,E≤N,∣T∣≤104​ 。

本题的意思是要我们查找负环,读入 小路 建双向边,虫洞 建单边然后spfa即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
const int N=5210;
int h[N],ne[N],e[N],idx,w[N],dist[N];
bool st[N];
int t;
int n,m,ww;
int cnt[N];
void add(int a,int b,int c){
	e[idx]=b; w[idx]=c; ne[idx]=h[a]; h[a]=idx++;
}
bool spfa(){
	queue <int> q;
	memset(dist,0x3f,sizeof(dist));
	for (int i = 1; i <= n; i ++ )
    {
        q.push(i);
        st[i] = true;
    }
	while(q.size()){
		int t=q.front(); q.pop();
		st[t]=0;
		for(int i=h[t];i!=-1;i=ne[i]){
			int j=e[i];
			if(dist[j]>dist[t]+w[i]){
				dist[j]=dist[t]+w[i];
				cnt[j]=cnt[t]+1;
				if(cnt[j]>=n){
					return 0;//当一个点进入队列超过n次时说明有负权回路。
				}
				if(!st[j]){
					st[j]=1;
					q.push(j);
				}
			}
		}
	}
	return 1;
}
int main(){
	cin>>t;
	while(t--){
		memset(h,-1,sizeof(h));
		memset(st,0,sizeof(st));
		memset(cnt,0,sizeof(cnt));
		idx=0;
		cin>>n>>m>>ww;
		for(int i=1;i<=m;i++){
			int a,b,c;
			cin >> a >> b >> c;
			add(a,b,c);
			add(b,a,c);
		}
		for(int i=1;i<=ww;i++){
			int a,b,c;
			cin >> a >> b >> c;
			add(a,b,-1*c);//边权要取正
		}
		  if (!spfa()) cout<<"YES"<<endl; 
		  else
		 cout<<"NO"<<endl;
	}
	return 0;
}

上一篇:XML基础


下一篇:使用John the ripper破解密码