hdu 1317 Bellman-Ford

参考:貌似网上没几个对的题解

1.http://blog.csdn.net/juststeps/article/details/8772653?reload

2.wiki:The transitive closure of a directed acyclic graph (DAG) is the reachability relation of the DAG and a strict partial order.

 

1.先用floyd求出各点间的可达性,这道题可以包含正负环,所以用floyd算法求出来的类似传递闭包的东西不是传递闭包

2.运行非队列版的Bellman-Ford算法,对每个点可能地松弛n-1次

3.再松弛一次,因为不包含正环的图的点肯定不能在松弛了(因为到每个点的路径上最多含n-1个不同的其它点),若某点还能松弛,则说明该图含正环,此时判断能否从源点到该点,能否从该点到终点(1求出的可达性),若两者都满足则winnable。

其它情况略。

问题:bford最后的for枚举每条边能保证从源点到达当前点/终点?

答:

1.因为有条件的d[i] + val[j] > 0 且 从源点出发不可达点初始化无穷小,所以i点从源点可达;

2.加上条件adj[i][j](i,j相邻)知j从i可达,再由d[j]<d[i]+val[j]知j点还可继续松弛,即j点在正环中(从而可使j点能量无穷大);

3.另外又有j与终点连通,所以j点与终点可达。

综上知,该情况下可从源点到终点,winnable。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<vector>
#include<cstdlib>
#include<algorithm>

using namespace std;

#define LL long long
#define ULL unsigned long long
#define UINT unsigned int
#define MAX_INT 0x7fffffff
#define MAX_LL 0x7fffffffffffffff
#define MAX(X,Y) ((X) > (Y) ? (X) : (Y))
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define INF 10000000
#define MAXN 111

int val[MAXN], n, d[MAXN];
bool reach[MAXN][MAXN], adj[MAXN][MAXN];

void floyd(){                           //求可达性
    int k, i, j;
    for(k=1; k<=n; k++)
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++) if(!reach[i][j])
                reach[i][j] = reach[i][j] || (reach[i][k] && reach[k][j]);
}

bool bford(int s, int t){
    int i, k, j;
    for(i=1; i<=n; i++) d[i]=-INF;  d[s]=100;

    for(k=0; k<n-1; k++){                   //bellman-ford 
        for(i=1; i<=n; i++)
            for(j=1; j<=n; j++) if(i!=j && adj[i][j]){
                int tw=d[i]+val[j];
                if(tw>0) d[j]=MAX(d[j], tw);
            }
    }

    for(i=1; i<=n; i++)                     //判断是否含正环
        for(j=1; j<=n; j++) if(adj[i][j] && i!=j && d[i]+val[j]>0 && d[j]<d[i]+val[j])
            if(reach[j][t]) return true;

    return d[t]>0;
}

int main(){
//    freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
//    freopen("C:\\Users\\Administrator\\Desktop\\out2.txt","w",stdout);
    while(scanf(" %d", &n)==1 && n!=-1){
        int m, u, v;
        memset(reach, 0, sizeof(reach));
        memset(adj, 0, sizeof(adj));
        for(u=1; u<=n; u++){
            scanf(" %d %d", val+u, &m);
            while(m--){
                scanf(" %d", &v);
                adj[u][v]=reach[u][v]=true;
             }
        }

        floyd();

        if(!reach[1][n]) printf("hopeless\n");
        else if(bford(1, n)) printf("winnable\n");
        else printf("hopeless\n");
    }
    return 0;
}

 

posted @ 2013-09-27 02:09  Ramanujan  阅读(653)  评论(0编辑  收藏  举报