题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1317
题目大意:有n个房间,编号1~n,房间之间有单向门连接。某人初始位于1号房间,且具有100点能量。此人要去n号房间,中途每经到一个房间Ri,其能量值会加上一个值ai,当其能量值小于等于0的时候会死掉。问此人能否到达n号房间。n<100, -100 <= ai <= 100。
分析:将房间看做结点,单向门看成单向边,形成一张有向图,问题转换为搜索一条从1号点能到达n号点的路径。
使用SPFA算法搜索最长路。如果图中不存在环,则找一条最长路即可。
否则,存在负环不影响结果。
如果存在正环,在顶点第n次进队列的时候,距离标记成无穷大,之后不在进队。这样,只要存在合理的路径,就一定能到达n点,不能到达说明无解。
参考代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 using namespace std; 5 #define N 110 6 #define inf 1000000000 7 8 vector<int>ve[N]; 9 10 int w[N]; 11 int Q[N*N]; 12 bool inq[N]; 13 int dis[N], cnt[N]; 14 int id; 15 bool spfa(int n) 16 { 17 for(int i = 1; i <= n; i++) 18 { 19 dis[i] = -inf, inq[i] = 0, cnt[i] = 0; 20 } 21 dis[1] = 100; 22 int top = 0; 23 Q[top++] = 1; 24 inq[1] = cnt[1] = 1; 25 for(int i = 0; i < top; i++) 26 { 27 int u = Q[i]; 28 inq[u] = 0; 29 if(dis[u]+w[u] <= 0) continue; 30 int m = ve[u].size(); 31 for(int j = 0; j < m; j++) 32 { 33 int v = ve[u][j]; 34 if(dis[v] < dis[u] + w[u]) 35 { 36 dis[v] = dis[u] + w[u]; 37 if(v == n) return true; 38 if(!inq[v]) 39 { 40 cnt[v]++; 41 if(cnt[v] > n) continue; 42 if (cnt[v] == n) 43 dis[v] = inf; 44 Q[top++] = v; 45 inq[v] = 1; 46 } 47 } 48 } 49 } 50 return false; 51 } 52 int main() 53 { 54 int n; 55 while(~scanf("%d", &n), ~n) 56 { 57 for(int i = 1; i <= n; i++) ve[i].clear(); 58 for(int i = 1; i <= n; i++) 59 { 60 int m, t; 61 scanf("%d", &w[i]); 62 scanf("%d", &m); 63 for(int j = 0; j < m; j++) 64 { 65 scanf("%d", &t); 66 ve[i].push_back(t); 67 } 68 } 69 bool res = spfa(n); 70 if(res) puts("winnable"); 71 else puts("hopeless"); 72 } 73 return 0; 74 }