POJ 1932 XYZZY

来源:互联网 发布:知乎阿波罗登月骗局 编辑:程序博客网 时间:2024/05/16 05:08

/*
在用BELLMAN时,当考虑某个点i时,如果当前从1到i的当前最大距离是负值,则这个点必须跳出来不能处理。因为此时这个点并不是活着的点,所以不能处理以它为起点的边。

如果不这样做可能会存在的错误CASE如下所示:
1->2->3->4
          ^   |
   6 <- 5 <
即:如果3,4,5可以构成一个正权环,但是2点的生命值为-1000,
那么当游戏者从1走到2时的当前生命值为100-1000=-900,即已经
为负了,是不能继续往下走的。否则如果不从2跳出的话,后续会找到
正权环3,4,5且从这个环到6是可达的,结果就会错误地输出WINNABLE,
但是这个图是HOPELESS的
*/
#include <iostream>
#include <queue>
#define MIN_VAL -9999999
#define MAX_N 105
using namespace std;

int dist[MAX_N + 1];
int can[MAX_N + 1];

struct set
{
    int len, val, prelen;
    int list[MAX_N + 1];
    int prelist[MAX_N + 1];
}sets[MAX_N + 1];
int n;
queue<int> bfsq;

void init()
{
    int i;
    for(i = 1; i <= n; i++)
    {
        can[i] = false;
        sets[i].val = 0;
        dist[i] = MIN_VAL;
        sets[i].prelen = 0;
        sets[i].len = 0;
    }
}

//寻找可达n的城市
void bfs()
{
    can[n] = true;
    while(!bfsq.empty()) bfsq.pop();
    bfsq.push(n);
    while(!bfsq.empty())
    {
        int curid = bfsq.front();
        bfsq.pop();

        int i, toid;
        for(i = 1; i <= sets[curid].prelen; i++)
        {
            toid = sets[curid].prelist[i];
            if(!can[toid])
            {
                can[toid] = true;
                bfsq.push(toid);
            }
        }
    }
}

//bell_man算法,注意正环
bool bell_man()
{
    bool tag[MAX_N + 1];
    memset(tag, 0, sizeof(tag));

    dist[1] = 100;
    tag[1] = true;
    int t, i, from, to;
    for(t = 1; t < n; t++)
    {
        for(from = 1; from <= n; from++)
        {
            //当前点位无生命点的话要跳出
            if(!tag[from]) continue;
            for(i = 1; i <= sets[from].len; i++)
            {
                to = sets[from].list[i];
                if(dist[from] + sets[to].val > dist[to])
                    dist[to] = dist[from] + sets[to].val;
                if(dist[to] > 0) tag[to] = true;
            }
        }
    }
    //if(dist[n] > 0) return true;
    for(from = 1; from <= n; from++)
    {
        if(!tag[from]) continue;
        for(i = 1; i <= sets[from].len; i++)
        {
            to = sets[from].list[i];
            if(dist[from] + sets[to].val > dist[to] && can[to])
                return true;
        }
    }
    if(dist[n] > 0) return true;
    return false;
}

int main()
{
    int i, j;
    while(scanf("%d", &n) && n != -1)
    {
        init();
        int to;
        for(i = 1; i <= n; i++)
        {
            scanf("%d%d", &sets[i].val, &sets[i].len);
            for(j = 1; j <= sets[i].len; j++)
            {
                scanf("%d", &to);
                sets[i].list[j] = to;
                sets[to].prelen++;
                sets[to].prelist[sets[to].prelen] = i;
            }
        }
        bfs();
        bool res;
        if(!can[1]) res = false;
        else
        {
            if(bell_man()) res = true;
            else res = false;
        }
        if(res) printf("winnable/n");
        else printf("hopeless/n");
    }
    return 0;
}