最短路 Bellman-Ford 边上权值任意的单源最短路

小B算法:

           怎样都好,就是不能图中包含负权值回路。。!

           假如图中有n个点,那么我们需要将图遍历(因为有n-1条边)n-1次(邻接表)或n-2(邻接矩阵,因为有初始化),每次遍历的时候,拿出一个点(u),再与其他个点比较(v),如果起始点到u距离大于  起始点到v的距离加上u到v的距离,那么就更新。直到所有的点拿完,再去遍历吧。。

判断存在负权值回路方法:

          遍历完n-1边以后,我们在更新一次所有点,如果还能更改,那么一定存在负权值回路。



*做了一些题,发现这个算法用于判断回路比较多,比如负权值回路与正权值回路。也可以结合flody算法来用,flody算法判断两点关系,是否可到达。然后在来用bellman-ford判断回路求解。如果在点i j存在回路,i到n可达,那么balabala....之类的用法。


code:

邻接矩阵    时间复杂度 O(n3)

#include<stdio.h>
#include<string.h>
#define MX 100000
int n,m,map[100][100],path[100],dist[100];
void bellman(int v0)
{
	for(int i=0;i<n;i++)
	{
		dist[i]=map[v0][i];
		if(map[v0][i]<MX)
			path[i]=v0;
		else
			path[i]=-1;
	}
	dist[v0]=0;
	for(int i=0;i<n-2;i++)       //遍历n-2遍
	{
		for(int j=0;j<n;j++)   //拿出一个点
		{
			if(j!=v0)
			{
				for(int k=0;k<n;k++)  //在拿出另外一个点,开始更新
				{
					if(map[k][j]<MX&&dist[k]+map[k][j]<dist[j])
					{
						path[j]=k;
						dist[j]=dist[k]+map[k][j];
					}
				}
			}
		}
	}
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i=0;i<n;i++)
			for(int j=0;j<n;j++)
				map[i][j]=MX;
		for(int i=0;i<m;i++)
		{
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			map[a][b]=c;
		}
		bellman(0);
		int pa[100];
		for(int i=0;i<n;i++)
		{
			printf("%d\n",dist[i]);
			int now=i,k=1;
			pa[0]=i;
			while(path[now]!=-1)
			{
				pa[k]=path[now];
				now=path[now];
				k++;
			}
			for(int j=k-1;j>0;j--)
				printf("%d ->",pa[j]);
			printf("%d\n",pa[0]);
		}
	}
	return 0;
}
邻接表判断有负权值回路


for(int i=0;i<n;i++)
{
	for(int j=0;j<n;j++)
		if(map[j][i]<MX&&dist[j]+map[j][i]<dist[i])
			return false;  //有负环回路
}
return true;  //没有负环回路




邻接表  时间复杂度 O(nm)

#include<stdio.h>
#include<string.h>
#define MX 1000000
int n,m,dist[100],path[100];
struct point 
{
	int u,v,w;
}eg[100];
void bellman(int v0)
{
	for(int i=0;i<n;i++)
	{
		path[i]=-1;
		dist[i]=MX;
	}
	dist[v0]=0;
	for(int i=0;i<n-1;i++)
	{
		for(int j=0;j<m;j++)
		{
			if(dist[eg[j].u]<MX&&dist[eg[j].u]+eg[j].w<dist[eg[j].v])
			{
				dist[eg[j].v]=dist[eg[j].u]+eg[j].w;
				path[eg[j].v]=eg[j].u;
			}
		}
	}
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		for(int i=0;i<m;i++)
			scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].w);
		bellman(0);
		for(int i=1;i<n;i++)
		{
			int now=i,k=1;
			int pa[100];pa[0]=i;
			printf("%d\n",dist[i]);
			while(path[now]!=-1)
			{
				pa[k]=path[now];
				now=path[now];
				k++;
			}
			for(int j=k-1;j>0;j--)
				printf("%d->",pa[j]);
			printf("%d\n",pa[0]);
		}
	}
	return 0;
}
邻接表判断负环回路

for(int i=0;i<m;i++)
{
	if(dist[eg[i].u]+eg[i].w<dist[eg[i].v])
		return false;   //存在
}
return true;  //不存在负环回路



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值