带负权图 bellman判环
为什么要循环V-1次?
答:因为最短路径肯定是个简单路径,不可能包含回路的,
如果包含回路,且回路的权值和为正的,那么去掉这个回路,可以得到更短的路径
如果回路的权值是负的,那么肯定没有解了
#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define ll __int64 using namespace std; struct node { int u,v; }e[10010]; int cnt,reach[110][110],w[110],n,d[110]; void floyd() { int i,j,k; for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { for(k=1;k<=n;k++) { reach[j][k]=reach[j][k]||(reach[j][i]&&reach[i][k]); } } } } int bellman() { int i,j,u,v; for(i=1;i<=n;i++) d[i]=-1000000000; d[1]=100; for(i=0;i<n-1;i++) { for(j=0;j<cnt;j++) { u=e[j].u; v=e[j].v; if(d[u]+w[v]>d[v]&&d[u]+w[v]>0) { d[v]=d[u]+w[v]; } } } for(i=0;i<cnt;i++) { u=e[i].u; v=e[i].v; if(d[u]+w[v]>d[v]&&d[u]+w[v]>0) { if(reach[v][n]) return 1; } } return d[n]>0; } int main() { int i,m,a; while(scanf("%d",&n)&&n!=-1) { memset(reach,0,sizeof reach); memset(w,0,sizeof w); cnt=0; for(i=1;i<=n;i++) { scanf("%d%d",&w[i],&m); while(m--) { scanf("%d",&a); reach[i][a]=1; e[cnt].u=i; e[cnt++].v=a; } } floyd(); if(reach[1][n]==0) { printf("hopeless\n"); continue; } if(bellman()) printf("winnable\n"); else printf("hopeless\n"); } return 0; }
原文:http://blog.csdn.net/u011032846/article/details/22639719