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; }