POJ 3259 Wormholes

题目:

Wormholes
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 27825 Accepted: 10012

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


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


题目大意:

给你n个点,有m条路是无向的(权值为正),w条路是有向的(权值为负),判断是否存在负权回路。


解题思路:

这是一个负权回路的判断问题,我们可以用Bellman-Ford算法开解决。Bellmall-Ford的基本思想是:

   // 该实现读入边和节点的列表,并向两个数组(distance和predecessor)中写入最短路径信息

   // 步骤1:初始化图
   for each vertex v in vertices:
       if v is source then distance[v] := 0
       else distance[v] := infinity
       predecessor[v] := null

   // 步骤2:重复对每一条边进行松弛操作
   for i from 1 to size(vertices)-1:
       for each edge (u, v) with weight w in edges:
           if distance[u] + w < distance[v]:
               distance[v] := distance[u] + w
               predecessor[v] := u

   // 步骤3:检查负权环
   for each edge (u, v) with weight w in edges:
       if distance[u] + w < distance[v]:
           error "图包含了负权环"

我们也可以用spfa来解决这个问题。


方法1代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <limits.h>
using namespace std;

const int MAXN = 510;
struct Eage
{
	int s, e, v;
};
Eage eage[5200];
int n, m, w, cnt, dis[MAXN];

int BellmanFord()
{
	for(int i = 1; i <= n; i++)
	{
		dis[i] = INT_MAX;
	}
	dis[1] = 0;
	for(int i = 1; i < n; i++)
	{
		for(int j = 0; j < cnt; j++)
		{
			if(dis[eage[j].s] < dis[eage[j].e] - eage[j].v)
			{
				dis[eage[j].e] = dis[eage[j].s] + eage[j].v;
			}
		}
	}
	for(int i = 0; i < cnt; i++)
	{
		if(dis[eage[i].s] < dis[eage[i].e] - eage[i].v)
		{
			return 1;
		}	
	}
	
	return 0;
}

int main()
{
	int f;
	scanf("%d", &f);
	
	while(f--)
	{
		cnt = 0;
		memset(eage, 0, sizeof(eage));
		memset(dis, 0, sizeof(dis));
		scanf("%d%d%d", &n, &m, &w);
		for(int i = 0; i < m; i++)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			eage[cnt].s   = a;
			eage[cnt].e   = b;
			eage[cnt++].v = c;
			eage[cnt].s   = b;
			eage[cnt].e   = a;
			eage[cnt++].v = c;
		}
		for(int i = 0; i < w; i++)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			eage[cnt].s   = a;
			eage[cnt].e   = b;
			eage[cnt++].v = -c;
		}
		printf("%s\n", BellmanFord() ? "YES" : "NO");
	}
	
	return 0;
}

方法2代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <limits.h>
using namespace std;

const int MAXN = 510;
struct Eage
{
	int e, v;
};
vector<Eage> eage[MAXN];
int n, m, w, dis[MAXN];

int spfa()
{
	int num[MAXN], vis[MAXN];
	memset(num, 0, sizeof(num));
	memset(vis, 0, sizeof(vis));
	dis[1] = 0; vis[1] = num[1] = 1;
	queue<int> q; q.push(1);
	
	while(!q.empty())
	{
		int x = q.front();
		q.pop(); vis[x] = 0;
		int size = eage[x].size();
		
		for(int i = 0; i < size; i++)
		{
			int e = eage[x][i].e, v = eage[x][i].v;
			if(dis[x] + v < dis[e])
			{
				dis[e] = dis[x] + v;
				if(!vis[e])
				{
					vis[e] = 1;
					num[e]++;
					if(num[e] >= n) return 1;
					q.push(e);
				}
			}
		}
	}
	return 0;
}

int main()
{
	int f;
	scanf("%d", &f);
	
	while(f--)
	{
		Eage tmp;
		scanf("%d%d%d", &n, &m, &w);
		for(int i = 1; i <= n; i++)
		{
			eage[i].clear();
			dis[i] = INT_MAX;
		}
		while(m--)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			tmp.e = b, tmp.v = c;
			eage[a].push_back(tmp);
			tmp.e = a, tmp.v = c;
			eage[b].push_back(tmp);
		}
		while(w--)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			tmp.e = b, tmp.v = -c;
			eage[a].push_back(tmp);
		}
		printf("%s\n", spfa() ? "YES" : "NO");
	}
	
	return 0;
}


或者:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <limits.h>
using namespace std;

const int MAXN = 510;
struct Eage
{
	int e, v;
};
vector<Eage> eage[MAXN];
int n, m, w, dis[MAXN];

int spfa()
{
	int num[MAXN], vis[MAXN];
	memset(num, 0, sizeof(num));
	memset(vis, 0, sizeof(vis));
	dis[1] = 0; vis[1] = num[1] = 1;
	queue<int> q; q.push(1);
	
	while(!q.empty())
	{
		int x = q.front();
		q.pop(); vis[x] = 0;
		for(vector<Eage>::iterator it = eage[x].begin(); it != eage[x].end(); it++)
		{
			if(dis[x] + it->v < dis[it->e])
			{
				dis[it->e] = dis[x] + it->v;
				if(!vis[it->e])
				{
					vis[it->e] = 1;
					q.push(it->e);
					num[it->e]++;
					if(num[it->e] >= n) return 1;
				}
			}
		}
		
	}
	return 0;
}

int main()
{
	int f;
	scanf("%d", &f);
	
	while(f--)
	{
		Eage tmp;
		scanf("%d%d%d", &n, &m, &w);
		for(int i = 1; i <= n; i++)
		{
			eage[i].clear();
			dis[i] = INT_MAX;
		}
		while(m--)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			tmp.e = b, tmp.v = c;
			eage[a].push_back(tmp);
			tmp.e = a, tmp.v = c;
			eage[b].push_back(tmp);
		}
		while(w--)
		{
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			tmp.e = b, tmp.v = -c;
			eage[a].push_back(tmp);
		}
		printf("%s\n", spfa() ? "YES" : "NO");
	}
	
	return 0;
}


方法2注意点:

1.如果,dis数组初始化为无穷大,spfa函数里 的判断条件要这么写:if(dis[x] + v < dis[e]),而不能写成if(dis[x] < dis[e]  -  v),因为v可以是负值,可能导致dis[e] - v溢出,以致于结果判断出错(巨坑,因为这个问题,我wa了20+次,简直无语),或者说,如果要用if(dis[x] < dis[e]  -  v)的话,可以把无穷大设的小一点也行

2.入队次数大于n时形成负权回路,if(num[e] >= n) return 1;


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值