hdu 1317:XYZZY

就是说给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 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值