POJ 3259 Wormholes 【Floyd判断负环】

POJ 3259 Wormholes 【Floyd判断负环】

题目大意:
FJ 有 N 块田野【编号 1…n】田野间有 M 条路【双向】
同时有 W 个虫洞,通过这个虫洞到达另一个田野,可以回到一段时间以前【单向】
问:FJ 是否能在田地中遇到以前的自己

具体思路:
双向路为正权,单向路为负权,判断图中是否存在负环,存在则可以遇到以前的自己,至于为什么上一篇博客有解释
可用spfa求解,但是spfa是针对单源点的,此题没有指定源点,因此无法ac
至于那些默认1号田野为出发点的能ac可能是因为题目给的测试数据是连通图
因此本题更适合用floyd判断负权(下方我也贴出spfa以1号为出发点的代码)
初始化到自身的时间为0到其它田野的时间为无穷,若存在负环,最终到自身的时间会被松驰为负值,(可以遇到以前的自己)

具体代码:

//floyd
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 505;
const int INF = 1e9;
int maps[N][N];
int F, n, m, w;

void init()
{
     
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			if (i == j) maps[i][j] = 0;	//初始化到自身的时间为0
			else maps[i][j] = INF;	//到其它田野的时间为无穷大
}
bool floyd()
{
     

	for(int k=1;k<=n;k++)
		for (int i = 1; i <= n; i++)
		{
     
			for (int j = 1; j <= n; j++)
				if (maps[i][j] > maps[i][k] + maps[k][j])
					maps[i][j] = maps[i][k] + maps[k][j];
			if (maps[i][i] < 0)return true;
		}
	return false;
}

int main()
{
     
	cin >> F;
	while (F--)
	{
     
		cin >> n >> m >> w;
		init();
		for (int i = 1; i <= m + w; i++)
		{
     
			int x, y, t;
			cin >> x >> y >> t;
			if (i <= m )
			{
     
				if(t < maps[x][y])//考虑重边
					maps[x][y] = maps[y][x] = t;
			}
			else maps[x][y] = -t;	//虫洞是单向的,其实我绝对这里也应该考虑重边,但是没有也能ac
		}
		if (floyd())printf("YES\n");
		else printf("NO\n");
	}

	return 0;
}

顺便贴出spfa的做法(1号为出发点)

//spfa
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 505;
const int INF = 1e9;
struct Node {
     
	int x, y, t;	//x->y这条路/虫洞耗时t
	Node(int x, int y, int t) {
      this->x = x, this->y = y, this->t = t; }
};
vector<Node> maps[N];
int visit[N];	//记录是否在队列中
int index[N];	//记录入队次数
int d[N];		//d[i]表示穿梭到田野i的时间
int F, n, m, w;
int flag = 0;

void spfa()
{
     
	for (int i = 1; i <= n; i++)
		visit[i] = 0, index[i] = 0, d[i] = INF;
	visit[1] = 1;
	index[1] = 1;
	d[1] = 0;
	queue<int> q;
	q.push(1);
	while (q.size())
	{
     
		int t = q.front();
		q.pop();
		visit[t] = 0;
		for (vector<Node>::iterator it = maps[t].begin(); it != maps[t].end(); it++)
		{
     
			if (d[it->y] > d[t] + it->t) {
     
				d[it->y] = d[t] + it->t;
				if (!visit[it->y]) {
     
					visit[it->y] = 1;
					q.push(it->y);
					index[it->y]++;
					if (index[it->y] > n) {
     
						flag = 1;
						return;
					}
				}
			}

		}
	}
}

int main()
{
     
	//freopen("C:\\Users\\Tsai\\Desktop\\in.txt", "r", stdin);
	cin >> F;
	while (F--)
	{
     
		cin >> n >> m >> w;
		for (int i = 1; i <= m + w; i++)
		{
     
			int x, y, t;
			cin >> x >> y >> t;
			if (i <= m) {
     
				maps[x].push_back(Node(x, y, t));	//路是双向的
				maps[y].push_back(Node(y, x, t));
			}
			else maps[x].push_back(Node(x, y, -t));	//虫洞是单向的
		}
		spfa();
		if (flag)printf("YES\n");
		else printf("NO\n");
		for (int i = 1; i <= n; i++)
			maps[i].clear();
		flag = 0;
	}

	return 0;
}

你可能感兴趣的:(最短路,OJ题解)