POJ 3259 Wormholes(bellman_ford判断负环)

POJ 3259 http://poj.org/problem?id=3259

题意:

农夫 FJ 有 N 块田地【编号 1...n】 (1<=N<=500)
田地间有 M 条路径 【双向】(1<= M <= 2500)
同时有 W 个孔洞,可以回到以前的一个时间点【单向】(1<= W <=200)
问:FJ 是否能在田地中遇到以前的自己

算法:bellman_ford 判断是否有负环

思路:

田地间的双向路径加边,权值为正
孔洞间的单向路径加边,权值为负【可以回到以前】
判断有向图是否存在负环
因为如果存在了负数环,时间就会不停的减少,
那么 FJ 就可以回到以前更远的地方,肯定能遇到以前的自己的

#ifndef ONLINE_JUDGE
#pragma warning(disalbe : 4996)
#endif
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 510;
const int maxw = 2500 * 2 + 200 + 10;
const int inf = 10000;
int d[maxn];
int n, m;

struct Edge {
	int u, v;
	int t;
}edge[maxw];

bool bellman_ford() {
	for (int i = 1; i <= n; ++i) d[i] = inf;
	d[1] = 0;//起点定为0

	for (int i = 1; i < n; ++i) {
		bool flag = true;
		for (int j = 0; j < m; ++j) {
			int u = edge[j].u;
			int v = edge[j].v;
			int t = edge[j].t;

			if (d[v] > d[u] + t) {//松弛操作
				d[v] = d[u] + t;
				flag = false;
			}
		}
		if (flag) return false;//如果当前轮不能松弛,直接判断没有负数环
	}

	for (int i = 0; i < m; ++i) 
		if (d[edge[i].v] > d[edge[i].u] + edge[i].t)
			return true;//如果仍然能够松弛则存在负环
	
	return false;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
	freopen("out.txt", "w", stdout);
#endif // !ONLINE_JUDGE
	int T;
	int M, W;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d%d", &n, &M, &W);
		m = 0;

		int u, v, t;
		for (int i = 1; i <= M; i++) //田地间的大路,加双边
		{
			scanf("%d%d%d", &u, &v, &t);
			edge[m].u = u;
			edge[m].v = v;
			edge[m++].t = t;

			edge[m].u = v;
			edge[m].v = u;
			edge[m++].t = t;
		}

		for (int i = 1; i <= W; i++) //孔洞,加单边
		{
			scanf("%d%d%d", &u, &v, &t);
			edge[m].u = u;
			edge[m].v = v;
			edge[m++].t = -t;
		}

		if (bellman_ford()) printf("YES\n"); //存在负数环
		else printf("NO\n");
	}
#ifndef ONLINE_JUDGE
	fclose(stdin);
	fclose(stdout);
	system("out.txt");
#endif // !ONLINE_JUDGE
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/RioTian/p/12913289.html