就是说给n个(n不超过100)房间,每个房间有一个能量数值(-100 ~ +100)以及若干扇门,每扇门通往另一个房间。玩家初始拥有100点能量,房间编号1 ~ n,玩家每到达一间房子就加上房间对应的能量数值。问玩家能否在能量用完之前从1到达n。
做法是先用floyd判断连通性,再用bellman-ford算法求路径。因为可能存在负权环路,所以spfa应该是没法做的。不过看到有人用spfa做出来了,那可能还是可以做的。本来刚开始是用bfs做的,不过判断环路会超时,当然也是有人用dfs做出来了。
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef struct edge {
int now , next ;
} Edge ;
const int inf = 1 << 20 ;
const int MAX = 105 ;
Edge edge[10005] = {0} ;
int n , num = 0 ;
int room[MAX] = {0} ;
int dis[MAX] = {0} ;
bool reach[MAX][MAX] = {0} ;
void init() {
num = 0 ;
memset(edge , 0 , sizeof(edge)) ;
memset(room , 0 , sizeof(room)) ;
memset(reach , 0 , sizeof(reach)) ;
}
void floyd() {
for (int k = 1 ; k <= n ; k ++) {
for (int i = 1 ; i <= n ; i ++) {
for (int j = 1 ; j <= n ; j ++) {
reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]) ;
}
}
}
}
bool ford() {
dis[1] = 100 ;
for (int i = 2 ; i <= n ; i ++) {
dis[i] = -inf ;
}
for (int k = 1 ; k <= n - 1 ; k ++) {
for (int i = 0 ; i < num ; i ++) {
int now = edge[i].now ;
int next = edge[i].next ;
if (dis[next] < dis[now] + room[next] && dis[now] + room[next] > 0) {
dis[next] = dis[now] + room[next] ;
}
}
}
for (int i = 0 ; i < num ; i ++) {
int now = edge[i].now ;
int next = edge[i].next ;
if (dis[next] < dis[now] + room[next] && dis[now] + room[next] > 0 && reach[next][n]) {
return 1 ;
}
}
return dis[n]>0 ;
}
int main() {
//freopen("in.txt" , "r" , stdin) ;
while (cin >> n) {
if (n == -1) break;
init() ;
for (int i = 1 ; i <= n ; i ++) {
int door ;
cin >> room[i] >> door ;
while (door --) {
int t ;
cin >> t ;
edge[num].now = i ;
edge[num].next = t ;
reach[i][t] = 1 ;
num ++ ;
}
}
floyd() ;
if (!reach[1][n]) cout << "hopeless\n" ;
else if (ford()) cout << "winnable\n" ;
else cout << "hopeless\n" ;
}
return 0 ;
}