hdu-1317 XYZZY---Floyd判连通+bellman最短路
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1317
题目大意:
题意:有n个房间(n<=100),每个房间有一个点权(第1号房间和第n号房间权值均为0),到达该房间时会自动获得该点权(可能为负权)。给出一些无向边。有一个人,初始有能量值100,初始位置是第1号房间,要走到第n号房间,且路途中不得使身上能量值小于或等于0。能到达第n个房间就算赢,问能否赢。
解题思路:
这里最坑的是第一号房间可能和最后一个房间连通不了。所以首先得判断连通性,再Bellman求最短路。
如果floyd判断房间1和房间n不连通,直接输出失败
如果在第n次还在松弛并且松弛的点可以到达终点n,说明存在正环且该正环能到达n,此时一定是成功的。
如果到达n的时候能量值为正数则成功,为0或者负数则失败
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 10000 + 10; 5 const int INF = 0x3f3f3f3f; 6 struct edge 7 { 8 int u, v, w; 9 edge(){} 10 edge(int u, int v, int w):u(u), v(v), w(w){} 11 }; 12 edge e[maxn]; 13 bool Map[105][105]; 14 int num[105], n, d[maxn], tot; 15 void addedge(int u, int v, int w) 16 { 17 e[tot++] = edge(u, v, w); 18 } 19 void floyd()//判断连通性 20 { 21 for(int k = 1; k <=n; k++) 22 { 23 for(int i = 1; i <= n; i++) 24 { 25 for(int j = 1; j <= n; j++) 26 { 27 Map[i][j] |= (Map[i][k]&Map[k][j]); 28 } 29 } 30 } 31 } 32 bool Bellman(int u) 33 { 34 memset(d, -INF, sizeof(d)); 35 d[u] = 100; 36 for(int i = 0; i < n; i++) 37 { 38 for(int j = 0; j < tot; j++) 39 { 40 int u = e[j].u, v = e[j].v, w = e[j].w; 41 if(d[u] + w > d[v] && d[u] > 0)//d[u]>0说明只有能量为正的点才可以对其相邻的边进行松弛 42 { 43 d[v] = d[u] + w; 44 if(i == n - 1 && Map[v][n]) 45 //i==n-1说明第n次迭代还在松弛,说明存在正环 46 //Map[v][n]=1说明松弛的点可以到达终点(这里改成Map[u][n]也是一样的,因为这两个的值是一样的,因为存在边<u, v>) 47 //满足上面两个条件说明存在一个正环,且该环可以到达终点 48 //可以一直在正环中运动使得能量值无穷大,最后就一定能到终点 49 return 1; 50 } 51 } 52 } 53 return d[n] > 0; 54 } 55 int main() 56 { 57 while(cin >> n && n != -1) 58 { 59 int t, x; 60 tot = 0; 61 memset(Map, 0, sizeof(Map)); 62 for(int i = 1; i <= n; i++) 63 { 64 cin >> num[i]; 65 cin >> t; 66 while(t--) 67 { 68 cin >> x; 69 Map[i][x] = 1; 70 } 71 } 72 for(int u = 1; u <= n; u++) 73 { 74 for(int v = 1; v <= n; v++) 75 { 76 if(Map[u][v])addedge(u, v, num[v]); 77 } 78 } 79 floyd(); 80 if(!Map[1][n])cout<<"hopeless"<<endl;//1-n直接不连通 81 else if(Bellman(1))cout<<"winnable"<<endl; 82 else cout<<"hopeless"<<endl; 83 } 84 return 0; 85 }
越努力,越幸运