大意:起始点100HP,给定n个房间,进入房间内加上或者减去 wHP,同一房间可以进入多次,问能否到达终点(HP大于0)。起点0,终点n-1。
思路:
假设图中没有环,如果要到达终点,则需让剩下的HP,如何让剩下的HP最大呢?求一遍最长路即可,然后判断d[n-1]是否大于0.
如果图中有正环,则一定可以走出去。因为我们一直绕着正环走的话HP可以到达INF,如此,我们找到正环中的点,然后判断正环中的点是否能够到达终点即可(连通),可以用dfs或者Flyod。
初始条件为:d[s] = 100(开始时HP为100,第一个房间和最后一个房间的HP为0)
图终点入队的约束条件是:(!inq[e.to] && d[e.to] > 0)表示当前点入队距离一定要大于0。
View Code
#include <iostream> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <cmath> #include <vector> #include <queue> #include <stack> #include <algorithm> #include <map> using namespace std; struct Edge { int from, to, dist; }; const int maxn = 110; const int INF = 0x3f3f3f3f; int energy[maxn]; struct BellManFord { int n, m; vector<Edge> edges; vector<int> G[maxn]; bool inq[maxn]; int d[maxn]; int p[maxn]; int cnt[maxn]; bool vis[maxn]; void init(int n) { this->n = n; for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); memset(vis, 0, sizeof(vis)); } void AddEdge(int from, int to, int dist) { edges.push_back((Edge) {from, to, dist}); m = edges.size(); G[from].push_back(m-1); } int dfs(int u, int t) { vis[u] = 1; for(int i = 0; i < G[u].size(); i++) { int v = edges[G[u][i]].to; //边遍历 if(vis[v]) continue; if(v == t) return 1; if(dfs(v, t)) return 1; } return 0; } bool spfa(int s, int t) { queue<int> Q; memset(inq, 0, sizeof(inq)); memset(cnt, 0, sizeof(cnt)); for(int i = 0; i <= n; i++) d[i] = (i == s)? 0:-INF; d[s] = 100; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = false; for(int i = 0; i < G[u].size(); i++) { Edge&e = edges[G[u][i]]; if(d[e.to] < d[u] + e.dist) { d[e.to] = d[u] + e.dist; p[e.to] = G[u][i]; if(!inq[e.to] && d[e.to] > 0) { Q.push(e.to); inq[e.to] = true; if(++cnt[e.to] > n) { if(d[t] > 0 || dfs(e.to, t)) return 1; else return 0; } } } } } return d[t] > 0; } }; BellManFord solver; int n, m; void read_case() { solver.init(n); int from, to, dist; for(int i = 0; i < n; i++) { scanf("%d%d", &dist, &m); while(m--) { scanf("%d", &to); to--; solver.AddEdge(i, to, dist); } } } void solve() { read_case(); int s = 0, t = n-1; int ans = solver.spfa(s, t); printf(ans == 1? "winnable\n":"hopeless\n"); } int main() { while(~scanf("%d", &n) && n != -1) { solve(); } return 0; }