acwing 904. 虫洞(spfa判断负环,单链表写法)

题目传送门

题目描述

农夫约翰在巡视他的众多农场时,发现了很多令人惊叹的虫洞。

虫洞非常奇特,它可以看作是一条 单向 路径,通过它可以使你回到过去的某个时刻(相对于你进入虫洞之前)。

农夫约翰的每个农场中包含 NN 片田地,MM 条路径(双向)以及 WW 个虫洞。

现在农夫约翰希望能够从农场中的某片田地出发,经过一些路径和虫洞回到过去,并在他的出发时刻之前赶到他的出发地。

他希望能够看到出发之前的自己。

请你判断一下约翰能否做到这一点。

下面我们将给你提供约翰拥有的农场数量 FF,以及每个农场的完整信息。

已知走过任何一条路径所花费的时间都不超过 1000010000 秒,任何虫洞将他带回的时间都不会超过 1000010000 秒。

输入格式

第一行包含整数 FF,表示约翰共有 FF 个农场。

对于每个农场,第一行包含三个整数 N,M,WN,M,W。

接下来 MM 行,每行包含三个整数 S,E,TS,E,T,表示田地 SS 和 EE 之间存在一条路径,经过这条路径所花的时间为 TT。

再接下来 WW 行,每行包含三个整数 S,E,TS,E,T,表示存在一条从田地 SS 走到田地 EE 的虫洞,走过这条虫洞,可以回到 TT 秒之间。

输出格式

输出共 FF 行,每行输出一个结果。

如果约翰能够在出发时刻之前回到出发地,则输出 YES,否则输出 NO

数据范围

1≤F≤51≤F≤5
1≤N≤5001≤N≤500,
1≤M≤25001≤M≤2500,
1≤W≤2001≤W≤200,
1≤T≤100001≤T≤10000,
1≤S,E≤N1≤S,E≤N

输入样例:

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

输出样例:

NO
YES

spfa判断负环

分析

代码

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring> 
using namespace std;
const int N = 510, M = 5210; // 
int h[N], e[M], w[M], ne[M], idx = 0; 
int dist[N]; // dist[i]表示到1到i的最短路的距离 
int cnt[N]; // cnt[i]表示到i点最短路的边数 
bool st[N]; // 
int n;
void add(int a, int b, int c)
{
	e[idx] = b;
	w[idx] = c;
	ne[idx] = h[a];
	h[a] = idx++;
}

bool spfa()
{
	memset(dist, 0, sizeof dist);
	memset(cnt, 0, sizeof cnt);
	memset(st, 0, sizeof st);
	
	queue<int> q;
	for(int i = 1; i <= n; i++)
	{
		st[i] = true;
		q.push(i);
	}
	
	while(q.size())
	{
		int t = q.front();
		q.pop();
		
		st[t] = false; // t不在队列中了
		
		for(int i = h[t]; i != -1; i = ne[i])
		{
			int j = e[i];
			if(dist[j] > dist[t] + w[i])
			{
				dist[j] = dist[t] + w[i];
				cnt[j] = cnt[t] + 1;
				
				if(cnt[j] >= n) return true;
				
				if(!st[j])
				{
					q.push(j);
					st[j] = true;	
				}	
			}	
		} 
	}
	return false;
}


int T, m1, m2;


void init()
{
	memset(h, -1, sizeof h);
	memset(e, 0, sizeof e);
	memset(ne, 0, sizeof ne);
	memset(w, 0, sizeof w);
	idx = 0;
}

int main()
{
	memset(h, -1, sizeof h);
	
	
	scanf("%d", &T);
	while(T--)
	{
		// 一定这里初始化,或者调用init() 
		memset(h, -1, sizeof h);
		idx = 0;
		
		
		int s, t, w;
		scanf("%d%d%d", &n, &m1, &m2);
		while(m1 --)
		{
			scanf("%d%d%d", &s, &t, &w);
			add(s, t, w), add(t, s, w); // 无向图	
		}	
		while(m2 --)
		{
			scanf("%d%d%d", &s, &t, &w);
			add(s, t, -w); // 负边 
		}
		if(spfa()) puts("YES");
		else	   puts("NO"); 
	} 
	return 0;
}

时间复杂度

参考文章

posted @ 2022-03-19 15:29  VanHope  阅读(38)  评论(0编辑  收藏  举报