hdu1317 负权最短路(Floyd+bellman)

首先要读懂题,做这个题时读题看样例琢磨了半天才明白= =;

题目的意思是,一个人从一号房间走到最后一个房间,每个房间有相应的能量值(可正可负),当走到这个房间的时候可以获取这个房间的能量值,如果走到最后一个房间时,人的能量值为正,则“winnable"”,否则的话就"hopeless",另外,这个人一开始自身有100点能量值,房间可以重复的走,且第一个房间和最后一个房间的能量值为零。

首先输入房间数N,然后有n行,每行输入i,j三个数,i代表这个房间所拥有的能量值,j代表这个房间一共可以走向其他的房间的个数,其次有j个数,代表可以走向哪几个房间。

解题思路:

首先用floyd遍历一下,标记那些点可以走向最后一个房间,如果从第一个无法走向最后一个,直接输出"hopeless"

其次,用bellman求最短路得方法改写成求最长路,求完后如果dis[n]是个负值,也就是人最多获取的能量还是个负值,就输出"hopeless"

另外,如果图中含有正权环,则一定能winnable,因为房间可以重复走,人可以重复回环走这个正权环来获取能量;但是需要判断一下如果有正权环了,这个环中所含的房间是否有一个能通向最后一个,如果有,才能下结论winnable

代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct
{
    int x,y;
} Edge;
int f[110][110],p[110];
Edge e[11000];

int floyd(int n)
{
    int i,j,k;
    for(k=1; k<=n; k++)
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++)
                if(f[i][k]&&f[k][j])
                    f[i][j]=1;
    if(f[1][n]==0)
        return 0;
    return 1;
}
int bellman(int n,int m)
{
    int dis[110];
    int inf=-9999999;
    int i,k;
    for(i=1; i<=n; i++)
        dis[i]=inf;
    dis[1]=100;
    for(k=1; k<n; k++)
        for(i=1; i<m; i++)//这里一定要注意,是i<m,没有等号,因为主函数中的m在结束循环时又自增了一,所以不需要加等号,一定要注意
        {
            if((dis[e[i].x]+p[e[i].y]>0)&&(dis[e[i].y]<dis[e[i].x]+p[e[i].y]))
                dis[e[i].y]=dis[e[i].x]+p[e[i].y];
        }
    for(i=1; i<m; i++)//判断正权环 ,记得m,弱在做的时候因为加了等号错了n遍T-T
    {
        if((dis[e[i].x]+p[e[i].y]>0)&&(dis[e[i].y]<dis[e[i].x]+p[e[i].y])&&f[e[i].y][n])
            return 1;
    }
    if(dis[n]>0)
        return 1;
    else
        return 0;
}

int main()
{
    int i,j,n,m,k;
    while(scanf("%d",&n),n!=-1)
    {
        m=1;
        memset(f,0,sizeof(f));
        for(i=1; i<=n; i++)
        {
            scanf("%d%d",&p[i],&j);
            while(j--)
            {
                scanf("%d",&k);
                f[i][k]=1;
                e[m].x=i;
                e[m].y=k;
                m++;
            }
        }
        if(floyd(n)==0)
            printf("hopeless\n");
        else
        {
            if(bellman(n,m))
                printf("winnable\n");
            else
                printf("hopeless\n");
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值