hdu1317 XYZZY(floyd、bellman_ford判环)(spfa)

因为有负数,所以不能直接求

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

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/yz467796454/article/details/77966054
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞