UVA10557 XYZZY

这题就是简单的 \(spfa\)最长路,跑到一个正环就直接输出 \(winnable\) ,最后只需要看 \(dis[n]\) 是否大于 \(0\) 就可以了。

但是在向队列加入新节点时,需要需要先判断新节点的 \(dis\) 是否大于 \(0\) ,这样才能保证在跑最长路时到每个节点时的能量大于 \(0\)

#include <bits/stdc++.h>

#define mkpr make_pair

using namespace std;


typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

const int maxn = 1e2 + 7;
const int inf  = 0x3f3f3f3f;

int n, w[maxn];
int h[maxn], ecnt;
struct edge {
	int v, nxt;
} e[maxn * maxn];
void add(int u, int v) {
	e[++ecnt] = edge{v, h[u]};
	h[u] = ecnt;
}

int dis[maxn], cnt[maxn];
bool inq[maxn];
queue<int> q;
bool spfa() {
	
	dis[1] = 100;
	q.push(1), inq[1] = 1;
	
	while (q.size()) {
		int u = q.front(); 
		q.pop(), inq[u] = 0;
		
		for (int i = h[u]; i; i = e[i].nxt) {
			int v = e[i].v;
			
			if (dis[v] < dis[u] + w[v]) {
				dis[v] = dis[u] + w[v];
				
				// 只有 dis[v] > 0 才能去松弛其他点 
				if (!inq[v] && dis[v] > 0) 
				    q.push(v), inq[v] = 1;	
				
				// 找到正环	
				if (++cnt[v] >= n) return 1;
			}
			
			// 存在某个时刻 dis[n] > 0 就代表可以到达 
			if (dis[n] > 0) return 1;
		}
	} 
	return 0;
}

void clear() {
	// 清图 
	memset(h, 0, sizeof(h));
	memset(e, 0, sizeof(e));
	ecnt = 0;
	
	// init spfa 
	memset(dis, -inf, sizeof(dis));
	memset(cnt, 0, sizeof(cnt));
	memset(inq, 0, sizeof(inq));
	while (q.size()) q.pop();
} 
void sol() {
	// 多组数据, 记得清空 
	clear(); 
	
	scanf("%d", &n);
	if (n == -1) exit(0);
	
	for (int i = 1; i <= n; ++i) {
		int v, k;
		scanf("%d%d", w + i, &k);
		while (k--) {
			scanf("%d", &v);
			add(i, v);
		}
	}
	
	if (spfa()) printf("winnable\n");
	else printf("hopeless\n");
} 
int main() {
	sol();
	return 0;
}
posted @ 2024-11-10 17:20  syzyc  阅读(5)  评论(0)    收藏  举报