【SPFA判负环】【Usaco2006 Dec】Wormholes

这篇博客讨论了Farmer John如何利用虫洞回到过去的场景,提出了一个利用SPFA算法判断是否存在负环的问题。文章介绍了输入输出格式,并阐述了SPFA判负环的原理,即通过计数器跟踪节点入队次数来检测负环。当节点入队次数超过一定阈值时,可推断存在负环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

Farmer John在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你
返回到过去的一个时刻(相对你进入虫洞之前)。Farmer John的每个农场有M条小路(无向边)连接着N
(从1..N标号)块地,并有W个虫洞。其中1<=N<=500,1<=M<=2500,1<=W<=200。
现在Farmer John想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。
Farmer John将向你提供F(1<=F<=5)个农场的地图。没有小路会耗费你超过10000秒的时间,当然也没有
虫洞回帮你回到超过10000秒以前。

Input

* Line 1: 一个整数 F, 表示农场个数。
* Line 1 of each farm: 三个整数 N, M, W。
* Lines 2..M+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地
中间有一条用时T秒的小路。
* Lines M+2..M+W+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地
中间有一条可以使John到达T秒前的虫洞。

Output

* Lines 1..F: 如果Farmer John能在这个农场实现他的目标,输出"YES",否则输出"NO"

Sample Input

2//2组数据
3 3 1
//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

分析

典型的spfa判负环

简单来说,spfa判负环就是用一个计数器来记录每个节点入队的次数。如果某个节点入队的次数超过了n次,那么一定存在负环

代码

#include<bits/stdc++.h>
using namespace std;
struct edge {
    int v, w, next;
} e[10010];
int head[517], cnt;

int t;
int n, m, w;
int dis[517];
bool vis[517];
int in[517];

inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
    while (ch >= '0' && ch <= '9') {x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar();}
    return x * f;
}

void init() {
    memset(dis, 0x3f3f3f, sizeof dis);
    memset(head, 0, sizeof head);
    memset(vis, false, sizeof vis);
    memset(in, 0, sizeof in);
    cnt = 0;
	
}

void insert(int u, int v, int w) {
    e[++cnt].v = v;
    e[cnt].w = w;
    e[cnt].next = head[u];
    head[u] = cnt;
}

bool spfa() {
    queue<int> q;
    dis[1] = 0;
    vis[1] = true;
    q.push(1);
    while (!q.empty()) {
	int u = q.front();
	q.pop();
	vis[u] = false;
	for (int i = head[u]; i; i = e[i].next) {
	    int v = e[i].v, w = e[i].w;
	    if (dis[v] > dis[u] + w) {
		dis[v] = dis[u] + w;
		if (!vis[v]) {
		    in[v]++;
		    if (in[v] > n) return true;
		    q.push(v);
		    vis[v] = true;
		}
	    }
        }
    }
    return false;
}

int main() {
    t = read();
    while (t--) {
	init();
	n = read(), m = read(), w = read();
	for (int i = 1; i <= m; i++) {
	    int u = read(), v = read(), w = read();
	    insert(u, v, w);
	    insert(v, u, w);
	}
	for (int i = 1; i <= w; i++) {
	    int u = read(), v = read(), w = read();
	    insert(u, v, -w);
	}
	if (spfa()) puts("YES");
	else puts("NO");
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值