带负权图 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;
}