因为有负数,所以不能直接求
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>
#define inf 999999999
using namespace std;
struct node{
int from,to;
}e[10005];
int a[105][105];
int first[105],nex[10005];
int cost[105];
int n,m;
void add(int len){
nex[len]=first[e[len].from];
first[e[len].from]=len;
}
void floyd(){
int u,v,w;
for(u=1;u<=n;u++){
for(v=1;v<=n;v++){
for(w=1;w<=n;w++){
if(!a[v][w]){
a[v][w]=a[v][u]&&a[u][w];
}
}
}
}
}
int bellmanford(int len){
int dis[105];
int i,k,from,to;
for(i=1;i<=n;i++){
dis[i]=-inf;
}
dis[1]=100;
for(k=0;k<n-1;k++){
for(i=0;i<len;i++){
from=e[i].from;
to=e[i].to;
if(dis[to]<dis[from]+cost[to]&&dis[from]+cost[to]>0)
dis[to]=dis[from]+cost[to];
}
}
for(i=0;i<len;i++){
from=e[i].from;
to=e[i].to;
if(dis[to]<dis[from]+cost[to]&&dis[from]+cost[to]>0&&a[to][n])//判断环,要判断这个环能到达终点
return 1;
}
return dis[n]>0;
}
int main(){
while(scanf("%d",&n)!=EOF){
if(n==-1)break;
int i,j;
int len=0;
memset(a,0,sizeof(a));
memset(e,0,sizeof(e));
memset(first,-1,sizeof(first));
memset(nex,-1,sizeof(nex));
memset(cost,0,sizeof(cost));
for(i=1;i<=n;i++){
int m;
scanf("%d%d",&cost[i],&m);
for(j=1;j<=m;j++){
int x;
scanf("%d",&x);
a[i][x]=1;
e[len].from=i;
e[len].to=x;
add(len);
len++;
}
}
floyd();
if(!a[1][n]){
printf("hopeless\n");
continue;
}
if(bellmanford(len))printf("winnable\n");
else printf("hopeless\n");
}
return 0;
}
还有一种方式是用spfa判断是否有负环,代码如下(来自http://www.cnblogs.com/littlepear/p/5657362.html)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 105;
const int INF = 0x3f3f3f3f;
int n;
int energy[maxn];
int power[maxn]; //记录到每一点的力量值
int cnt[maxn]; //记录访问每一个点的次数
bool g[maxn][maxn];
bool reach[maxn][maxn];
void floyd()
{
for(int k = 1; k<=n; k++)
for(int i = 1; i<=n; i++)
for(int j = 1; j<=n; j++)
if(reach[i][j]||(reach[i][k]&&reach[k][j])) reach[i][j] = true;
}
bool spfa(int s)
{
queue<int> q;
memset(power,0,sizeof(power));
power[s] = 100;
memset(cnt,0,sizeof(power));
q.push(s);
while(!q.empty())
{
int v = q.front();
q.pop();
cnt[v]++;
if(cnt[v]>=n) return reach[v][n]; //有正环
for(int i = 1; i<=n; i++)
{
if(g[v][i]&&power[i]<power[v]+energy[i]&&power[v]+energy[i]>0)
{
power[i] = power[v]+energy[i];
q.push(i);
}
}
}
return power[n]>0;
}
void solve()
{
while(scanf("%d",&n)!=EOF&&n!=-1)
{
memset(g,false,sizeof(g));
memset(reach,false,sizeof(reach));
for(int i = 1; i<=n; i++)
{
int k,door;
scanf("%d %d",&energy[i],&k);
for(int j = 1; j<=k; j++)
{
scanf("%d",&door);
g[i][door] = true;
reach[i][door] = true;
}
}
floyd();
if(!reach[1][n])
{
printf("hopeless\n");
continue;
}
if(spfa(1))
{
printf("winnable\n");
}
else
{
printf("hopeless\n");
}
}
}
int main()
{
solve();
return 0;
}