poj-3259 bellman-ford

题意:
John的农场里N块地,M条路连接两块地,W个虫洞;路是双向的,虫洞是一条单向路,会在你离开之前把你传送到目的地,
就是当你过去的时候时间会倒退Ts。我们的任务是知道会不会在从某块地出发后又回来,看到了离开之前的自己。
简化下,就是看图中有没有负权环。
解题:

bellman_ford和spfa算法均可,但是实现效率bellman_ford更简单,也更容易,虽然spfa算法是bellman_ford的增强版,但是在

判断图中是否存在负权回路的问题上要逊色于bellman_ford算法

 

bellman:

#include <stdio.h>

#define maxN 502
#define maxM 2702
#define inf 1000000000

struct EDGE 
{
	int u,v,w;
}edge[2 * maxM];
int dis[maxN];

int N, M, W;
int edgeNum;

void Init()
{
	for (int i = 0; i <= N; ++ i)
	{
		dis[i] = inf;
	}
}

bool bellMan(void)
{
	bool flag;
	for (int i = 0; i < N - 1; ++ i)
	{
		flag = false;
		for (int j = 0; j < edgeNum; ++ j)
		{
			if (dis[edge[j].v] > dis[edge[j].u] + edge[j].w)//松弛
			{
				dis[edge[j].v] = dis[edge[j].u] + edge[j].w;
				flag = true;
			}
		}
		if (!flag)//存在负权回路
		{
			break;
		}
	}
	for (int i = 0; i < edgeNum; ++ i)
	{
		if(dis[edge[i].v] > dis[edge[i].u] + edge[i].w)
			return true;
	}
	return false;
}

int main()
{
	int F;
	scanf("%d", &F);
	while (F --)
	{
		scanf("%d%d%d", &N, &M, &W);
		edgeNum = 0;
		Init();
		int u,v,w;
		for (int i = 1; i <= M; ++ i)
		{
			scanf("%d%d%d", &u, &v, &w);//正权双向
			edge[edgeNum].u = u;
			edge[edgeNum].v = v;
			edge[edgeNum].w = w;
			edgeNum ++;
			edge[edgeNum].u = v;
			edge[edgeNum].v = u;
			edge[edgeNum].w = w;
			edgeNum ++;
		}
		for (int i = 1; i <= W; ++ i)
		{
			scanf("%d%d%d", &u, &v, &w);
			edge[edgeNum].u = u;
			edge[edgeNum].v = v;
			edge[edgeNum].w = -w;//负权
			edgeNum ++;
		}
		if(bellMan())  
			printf("YES\n");
		else  
			printf("NO\n");

	}
	return 0;
}

spfa 引用

#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<queue> 
#define MA 6000 
#define INF 0x7FFFFFF 
using namespace std; 
int nxt[MA],head[MA],ep; 
struct E 
{ 
    int v,w; 
}; 
E e[MA];/* 存储边的信息 */
int N,M,W; 
void addEdge(int cu,int cv,int cw) 
{ 
    ep++; 
    e[ep].v=cv; 
    e[ep].w=cw; 
    nxt[ep]=head[cu]; 
    head[cu]=ep; 
} 
void init() 
{ 
    memset(head,-1,sizeof(head)); 
    ep=0; 
    scanf("%d%d%d",&N,&M,&W); 
    int cu,cv,cw; 
    while(M--) 
    { 
        scanf("%d%d%d",&cu,&cv,&cw); 
        addEdge(cu,cv,cw); 
        addEdge(cv,cu,cw); 
    } 
    while(W--) 
    { 
        scanf("%d%d%d",&cu,&cv,&cw); 
        addEdge(cu,cv,-cw); 
    } 
} 
int spfa() 
{ 
    int cnt[MA],inq[MA],dis[MA]; 
    memset(cnt,0,sizeof(cnt));/* 计算点被走过了多少次 */ 
    memset(inq,0,sizeof(inq));/* 判断该点是否在队列中 */
    for(int i=2;i<=N;i++) dis[i]=INF; 
    dis[1]=0; 
    inq[1]=1; 
    cnt[1]=1; 
    queue<int>q; 
    q.push(1); 
    while(!q.empty()) 
    { 
        int u=q.front(); q.pop(); 
        inq[u]=0;/* 将该点出队 */
        for(int p=head[u];p!=-1;p=nxt[p]) 
        { 
            if(dis[e[p].v]>dis[u]+e[p].w) 
            { 
                dis[e[p].v]=dis[u]+e[p].w; 
                if(!inq[e[p].v]) 
                { 
                    inq[e[p].v]=1;/* 将该点入队 */
                    /* 如果某一点被走过的次数大于n-1次,证明存在负权回路 */
                    if(++cnt[e[p].v]>=N) return 1; 
                    q.push(e[p].v); 
                } 
            } 
        } 
    }  
    return 0; 
} 
int main() 
{ 
    int t; 
    scanf("%d",&t); 
    while(t--) 
    { 
        init(); 
        if(spfa()) printf("YES\n"); 
        else printf("NO\n"); 
    } 
    return 0; 
} 

 

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