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;
}

浙公网安备 33010602011771号