题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1317
题意:自己本身带100的活力值,每进一个房间就加上这个房间的活力值,判断能否在活力值大于0的情况下走出房间;
思路:首先判断起点和终点是否连通,如果连通就判断是否有正环,如果有正环要判断正环内有没有点能够到达终点,最后判断d【终点】是不是大于0;这里要注意的是,中途如果活力值为0就算失败,所以,如果d不是正数就不松弛边;还有一个就是,并不是判断有正环就一定能够赢,如果环内没有点能够和终点连通的话,活力值再大也没用;
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Maxn = 110;
const int INF = 0x3f3f3f3f;
int u[Maxn*Maxn],v[Maxn*Maxn],w[Maxn],used[Maxn][Maxn],V,M,d[Maxn];
bool check () {
for (int k = 1; k <= V; ++k) {
for (int i = 1; i <= V; ++i) {
for (int j = 1; j <= V; ++j) {
used[i][j] = (used[i][j] || (used[i][k] && used[k][j]));
}
}
}
if(used[1][V]) return true;
else return false;
}
bool solve () {
int from,to;
for (int i = 1; i <= V; ++i) d[i] = -INF;
d[1] = 100; bool falg;
for (int i = 1; i <= V; ++i) {
falg = false;
for (int j = 1; j <= M; ++j) {
from = u[j]; to = v[j];
if(d[from]+w[to] > 0 && d[to] < d[from]+w[to]) {
d[to] = d[from]+w[to];
falg = true;
if(i == V && used[to][V]) return true; // 成环的情况下判断环内每一个点是否和终点连通
}
}
if(!falg) break;
}
if(d[V] > 0) return true;
return false;
}
int main (void) {
int m,tmp;
while (scanf("%d",&V) != EOF) {
if(V == -1) break;
memset(w,0,sizeof(w));
memset(used,0,sizeof(used));
M = 0;
for (int i = 1; i <= V; ++i) {
scanf("%d%d",&w[i],&m);
for (int j = 1; j <= m; ++j) {
scanf("%d",&tmp);
if(used[i][tmp]) continue;
used[i][tmp] = 1;
u[++M] = i; v[M] = tmp;
}
}
if(!check()) printf("hopeless\n");
else if(solve ()) printf("winnable\n");
else printf("hopeless\n");
}
return 0;
}