XYZZY HDU - 1317

Floyd判断连通性 + spfa判断正环。
题目描述:有一百个房间,你的初始能量值是100,从起点1开始出发,判断你能不能到达第100个房间。不能到达的情况是,在中途的过程中生命值降为0及以下,或者是没有路能够到达房间100。注意:题目中是单项边。而且同一个房间可以进入多次。
解题分析:先用Floyd判断一下能否到达。如果能到达的话,看看到达终点的生命值是否大于0。因为要尽量能活到那,所以求得不是最短路了,而是最长路。所以原版的spfa的写法大于小于反过来就行。因为松弛的时候,要求得是生命值大于0,而且是求最长路,所以d[t] + pic[t][i] <= 0 的话就不会进行松弛,所以也就不存在负圈的问题了,而是存在正圈。当发现了正圈的时候不是直接返回true,我在这个地方WA了好多次,因为一旦发现了正圈则说明这个点一定能够在这个圈内,而且起点是能够到达这个点的,但是因为此题是单向边,即便有正圈,也不能确定一定能到达终点。比如说,从起点到终点
的路径中不过包含圈内的任何点的话,则即便有圈也不能确定能否到达终点。此时正确的处理应该是,判断圈内的点能否到达终点。

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 100 + 10;
bool graph[maxn][maxn];
int pic[maxn][maxn];
int enqueue[maxn];
int d[maxn];
int used[maxn];
int n;

void init()
{
    memset(graph,false,sizeof(graph));
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= n; j++)
        {
            pic[i][j] = -INF;
        }
    }
    memset(enqueue,0,sizeof(enqueue));
    for(int i = 1; i <= n; i++) d[i] = -INF;
    memset(used,0,sizeof(used));
}

bool spfa()
{
    d[1] = 100;
    queue <int> q;
    q.push(1);
    used[1] = 1;
    enqueue[1]++;
    while(!q.empty())
    {
        int t = q.front();
        q.pop();
        used[t] = 0;
        for(int i = 1; i <= n; i++)
        {
            if(pic[t][i] != -INF)
            {
                if(d[i] < d[t] + pic[t][i] && d[t] + pic[t][i] > 0)
                {
                    d[i] = d[t] + pic[t][i];
                    if(!used[i])
                    {
                        q.push(i);
                        enqueue[i]++;
                        used[i] = 1;
                        if(enqueue[i] > n)
                        {
                            return graph[i][n];
                        }
                    }
                }
            }
        }
    }
    return d[n] > 0;
}

int main()
{
    while(cin >> n && n != -1)
    {
        init();
        int m,y,w;
        for(int i = 1; i <= n; i++)
        {
            cin >> w >> m;
            for(int j = 0; j < m; j++)
            {
                cin >> y;
                graph[i][y] = 1;
                pic[i][y] = w;
            }
        }
        for(int k = 1; k <= n; k++)
        {
            for(int i = 1; i <= n; i++)
            {
                for(int j = 1; j <= n; j++)
                {
                    graph[i][j] = graph[i][j] || graph[i][k]&&graph[k][j];
                }
            }
        }
        if(!graph[1][n]) printf("hopeless\n");
        else
        {
            if(spfa()) printf("winnable\n");
            else printf("hopeless\n");
        }
    }
    return 0;
}

在正圈那个地方WA了好多次,,智商啊。


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值