题目大意:有n个房间,房间编号从1~n,每个房间都有能量,以及下一步到达的房间,一个人从1号房间出发,初始能量为100,到达每个房间,得到其中的能量,重复到达可重复获得能量。要到达n号房间,可能吗?其中能量始终大于0。
解题思路:解法一:bfs,并限制一个能量上限,不然可能会死循环tle。看了陈帆的题解。解法二:spfa,普通的spfa的路是由许多u[i]到v[i]距离为w[i],构建邻接表的。而这题简化了,u[i]每一行为编号,故可以用临时变量代替,v[i]为每次输入的数,w[i]对应first[i]。spfa的循环中要保证不进入正环无法出来,设置一个变量cnt[i]表示i进入队列的次数,一个数最多进入t次,因为它是由其他t-1个first来松弛的。
ac代码:
#include <iostream> #include <cstring> #include <queue> using namespace std; struct pos{ int eng; int num; int goal[105]; }p[105]; struct node{ int power; int aim; }; int n, vis[105]; queue <node>qu; bool bfs() { while (!qu.empty()) qu.pop(); memset(vis, 0, sizeof(vis)); node temp; temp.power = 100; temp.aim = 1; vis[1] = 100; qu.push(temp); while (!qu.empty()){ temp = qu.front(); qu.pop(); for (int i=0; i<p[temp.aim].num; i++){ node tt; tt.aim = p[temp.aim].goal[i]; tt.power = p[temp.aim].eng + temp.power; if (vis[tt.aim] < tt.power && tt.power > 0 && tt.power < 10000){ if (tt.aim == n) return true; vis[tt.aim] = tt.power; qu.push(tt); } } } return false; } int main() { while (scanf("%d", &n)!=EOF && n != -1){ for (int i=1; i<=n; i++){ scanf("%d%d", &p[i].eng, &p[i].num); for (int j=0; j<p[i].num; j++) scanf("%d", &p[i].goal[j]); } if (bfs()) printf("winnable\n"); else printf("hopeless\n"); } return 0; }
#include <iostream> #include <queue> #include <cstring> using namespace std; queue <int>qu; int t, n, m, vis[105], v[10005], w[10005], cnt[10005]; int dis[105], first[105], Next[10005], cur, temp; void spfa() { int s, p, k; while (!qu.empty()) qu.pop(); cnt[1]++; qu.push(1); while (!qu.empty()){ s = qu.front(); vis[s] = 0; qu.pop(); if (cnt[s] > t) continue; if (cnt[s] == t) dis[s] = 10005; p = first[s]; while (p != -1){ k = v[p]; if (dis[k] < dis[s] + w[k] && dis[s] + w[k] > 0){ dis[k] = dis[s] + w[k]; if (!vis[k]){ vis[k] = 1; cnt[k]++; qu.push(k); } } p = Next[p]; } } } int main() { while (scanf("%d", &t) != EOF && t > 0){ cur = 1; memset(first, -1, sizeof(first)); memset(dis, 0, sizeof(dis)); memset(vis, 0, sizeof(vis)); memset(cnt, 0, sizeof(cnt)); dis[1] = 100; for (int i=1; i<=t; i++){ scanf("%d%d", &w[i], &m); for (int j=1; j<=m; j++){ scanf("%d", &v[cur]); Next[cur] = first[i]; first[i] = cur; cur++; } } spfa(); if (dis[t] > 0) printf("winnable\n"); else printf("hopeless\n"); } return 0; }