POJ3259 回到过去(带负权的单源最短路径)

有N个农场,它们之间有M条普通的双向路径,同时有W条单向“虫洞”,通过普通路径需要花费时间,但通过虫洞却可以回到过去。问能否从任意一个点出发,通过某些普通路径或者“虫洞”再回到起始位置,使到达的时间早于出发的时间。

这是带负权的单源最短路径的入门题,按题目给定的边建好图,从任意一点起点开始,使用Bellman-Ford算法运行一遍,判断有没有回路就可以了。

#include <iostream>
#include <cstdio>
#include <climits>
#include <algorithm>
using namespace std;

const int N = 505;
const int E = 5205;
const int MAX = 0xfffffff;
struct Edge
{
	int beg;
	int end;
	int dis;
};
Edge edge[E];
int mindis[N];
int n, e;

bool relax(int beg, int end, int dis)
{
	if (mindis[beg] + dis < mindis[end])
	{
		mindis[end] = mindis[beg] + dis;
		return true;
	}
	return false;
}

bool bellman_ford(int s)
{
	bool flag;
	for (int i = 0; i < n; ++i) mindis[i] = MAX;
	mindis[s] = 0;
	for (int i = 0; i < n - 1; ++i)
	{
		flag = false;
		for (int j = 0; j < e; ++j)
		{
			if (relax(edge[j].beg, edge[j].end, edge[j].dis)) flag = true;
		}
		if (!flag) break;
	}
	for (int i = 0; i < e; ++i)
	{
		if (relax(edge[i].beg, edge[i].end, edge[i].dis)) return false;
	}
	return true;
}

void addedge(int u, int v, int dis)
{
	edge[e].beg = u;
	edge[e].end = v;
	edge[e].dis = dis;
	++e;
}

int main()
{
	int T;
	int m, w;
	int u, v, dis;
	scanf("%d", &T);
	while (T--)
	{
		scanf("%d%d%d", &n, &m, &w);
		e = 0;
		for (int i = 0; i < m; ++i)
		{
			scanf("%d%d%d", &u, &v, &dis);
			--u;
			--v;
			addedge(u, v, dis);
			addedge(v, u, dis);
		}
		for (int i = 0; i < w; ++i)
		{
			scanf("%d%d%d", &u, &v, &dis);
			--u;
			--v;
			addedge(u, v, -dis);
		}
		if (bellman_ford(0)) printf("NO\n");
		else printf("YES\n");
	}
	return 0;
}


你可能感兴趣的:(POJ3259 回到过去(带负权的单源最短路径))