spfa 判断负环poj3259

题目链接:http://poj.org/problem?id=3259

Description

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ's farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..NM (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.

Input

Line 1: A single integer, FF farm descriptions follow. 
Line 1 of each farm: Three space-separated integers respectively: NM, and W 
Lines 2..M+1 of each farm: Three space-separated numbers (SET) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path. 
Lines M+2..M+W+1 of each farm: Three space-separated numbers (SET) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.

Output

Lines 1..F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).

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

Hint

For farm 1, FJ cannot travel back in time. 
For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.

题目大意:给出一个混合图(无向图+有向图),无向图事路,有向图是虫洞,虫洞可以回到过去;

如果能回到过去(经过虫洞后原点时间减少了)能则输出yes,否则输出no

大佬们有好多fang方法判断负环,但是我目前只会一种QAQ。。

spfa模板判断fu'h负环,

首先输入该地图,然后从一个点开始查找最短路,之后就是套用spfa模板了,有负环的存在返回1,无返回0;

对于模板,分为三个步骤

初始化:首先初始化数组shuaxin(用来记录最短路)为INF,biaoji(用于标记是否在队列)为0(不在),num(记录某一点进入队列的次数)为0;

起点入列:

循环判断:取出队首元素,取消标记(不在队列),利用邻接矩阵刷新最短距离,对于没有入列但可以入列de的的点,入列,标记,判断是否该点重复使用n次,ru'g如果重复使用,说明有fu'h负环,返回1;如果走完全程仍没有重复次数>n的,则代表代表没有负环。

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
//#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<iostream>  
#include<algorithm>  
using namespace std;  
  
#define ll long long  
#define INF 0x3f3f3f3f  
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
#define mod 1000000


int shuzu[510][510];
int shuaxin[510],num[510];
bool biaoji[510];
int n,m,w;

int spfa(int x)
{
	clean(biaoji,0);
	clean(num,0);
	clean(shuaxin,INF);
	queue<int> que;
	while(que.size())
		que.pop();
	//初始化完成
	biaoji[x]=1;
	shuaxin[x]=0;
	num[x]=1;
	que.push(x);
	//起点入列 
	while(que.size())
	{
		int can=que.front();//以改点为起点判断 刷新 
		que.pop();
		biaoji[can]=0;
		for(int i=1;i<=n;++i)
		{
			if(shuaxin[can]+shuzu[can][i]<shuaxin[i])
			{
				shuaxin[i]=shuzu[can][i]+shuaxin[can];//刷新 
				if(biaoji[i]==0)//判断 改点是否在队列 
				{
					biaoji[i]=1;
					num[i]++;//重复++ 
					if(num[i]>n)
						return 1;//有负环 
					que.push(i);
				}
				
			}
		}
	}
	return 0;
	
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		clean(shuzu,INF);
		
		cin>>n>>m>>w;
		for(int i=0;i<m;++i)
		{
			int s,e,l;
			cin>>s>>e>>l;
			if(shuzu[s][e]>l)
			{
				shuzu[s][e]=l;
				shuzu[e][s]=l;
			}
		}
		for(int i=0;i<w;++i)
		{
			int s,e,l;
			cin>>s>>e>>l;
			shuzu[s][e]=-l;//虫洞 
		}
		if(spfa(1))
			cout<<"YES"<<endl;
		else
			cout<<"NO"<<endl;
	}
}

后来又碰见这道题了,用邻接表写了一下,一开始甚至习惯性的想用优先队列。。。果然太年轻,spfa是用先进先出的队列,对每个点进行松弛操作后,判断队列中没有该元素,放入队列,若一个点重复放入n次以上,则说明有负环,而对于优先队列来说,它是按照一定的优先级出队的,因此一个点可能没有影响到队列中的其他点(实际上它应该要影响到)(应该大概解释的清楚了吧。。)ac:

#include<stdio.h>
#include<string.h>  
#include<math.h>  
  
//#include<map>   
//#include<set>
#include<deque>  
#include<queue>  
#include<stack>  
#include<bitset> 
#include<string>  
#include<iostream>  
#include<algorithm>  
using namespace std;  

#define ll long long  
#define INF 0x3f3f3f3f  
#define mod 1000000007
//#define max(a,b) (a)>(b)?(a):(b)
//#define min(a,b) (a)<(b)?(a):(b) 
#define clean(a,b) memset(a,b,sizeof(a))// 水印 
struct node{
	int ed,t;
	node(int _ed=0,int _t=0):ed(_ed),t(_t){}
};
//struct cmp{
//	bool operator ()(const node &a,const node &b){
//		return a.t<b.t;
//	}
//};

vector<node> vec[510];
bool ves[510];
int d[510],num[510];
int n,m,w;

bool spfa(int str)
{
	clean(ves,0);
	clean(d,INF);
	clean(num,0);
	//priority_queue<node,vector<node>,cmp> que;
	queue<int> que;
	while(que.size())
		que.pop();
	//初始化 
	ves[str]=1;
	d[str]=0;
	num[str]=1;
	que.push(str);
	//que.push(node(str,0));
	//入队 &&标记 
	while(que.size())
	{
		//int can=que.top().ed;
		int can=que.front();
		que.pop();
		ves[can]=0;
		//出队&&标记 
		for(int i=0;i<vec[can].size();++i)
		{
			node e=vec[can][i];
			if(d[e.ed]>d[can]+e.t)
			{
				d[e.ed]=d[can]+e.t;
				if(ves[e.ed]==0)
				{
					//que.push(node(e.ed,d[e.ed]));
					que.push(e.ed);
					ves[e.ed]=1;
					num[e.ed]++;
					if(num[e.ed]>n)
						return 1;
					
				}
			}
		}
	}
	return 0;
	
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		for(int i=0;i<510;++i)
			vec[i].clear();
		cin>>n>>m>>w;
		for(int i=0;i<m;++i)
		{
			int s,e,t;
			cin>>s>>e>>t;
			vec[s].push_back(node(e,t));
			vec[e].push_back(node(s,t));
		}
		for(int i=0;i<w;++i)
		{
			int s,e,t;
			cin>>s>>e>>t;
			vec[s].push_back(node(e,-t));
		}
		if(spfa(1))
			cout<<"YES"<<endl;
		else
			cout<<"NO"<<endl;
	}
	
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值