Bellman-Ford(最短路径解决负边权问题讲述)

解决这类问题的核心思想就是通过中间点的松弛来使路径变短(这好像和Floyd以及单元最短路径有些相似),不过此种算法是遍历n-1遍每一条边(可能不用这么多,为保险起见最多是这样不过这也是可以优化的)
还是先看一下核心代码:

for(int k=1; k<=n-1; k++)//遍历n-1次
  //遍历n-1遍是因为在n个顶点的路径中任意两点之间的最短路径最多只
  //可能包含n-1条边(最多只可能通过这么多的路径是两点之间的距离
  //变为最短)
		   for(int i=1; i<=m; i++)
		   {
		   	 if(dis[v[i]]>dis[u[i]]+w[i])
		   	 //核心判断看dis[v[i]即1号顶点到v[i]之间的距离是否可
		   	 //以通过1号点到u[i]再到v[i]来使路径变短
		   	   dis[v[i]]=dis[u[i]]+w[i];
		   }

下面还是来举个例子帮助理解:
我们给出一组数据

2 3 2
1 2 -3
1 5 5
4 5 2
3 4 3

dis数组初始状态:(1表示无穷大)
1 2 3 4 5
dis 0 1 1 1 1
下面来进行第一轮松弛:
dis[3]=无穷大dis[2]也是无穷大(注意此时dis[2]还不等与-3)+2因此不能松弛,下一组数dis[2]=无穷大但是dis[1]±3=-3满足松弛条件,dis[2]变为-3,下一组数dis[5]为无穷大通过dis[1]+w[i]=5满足条件变为5,后面的也是这一种做法,自行演示;
第一次后数组变为:
1 2 3 4 5
dis 0 -3 1 1 5
按照同样方法对其进行一条边一条边的遍历,(还是从2 3 2
)那一条开始
第二次数组变化:
1 2 3 4 5
dis 0 -3 -1 2 5
第三次变化:
1 2 3 4 5
dis 0 -3 -1 2 4
第四次变化:
1 2 3 4 5
dis 0 -3 -1 2 4
最后一组即为1号点到各条边之间的最小距离
AC代码为

#include<stdio.h>
int inf=99999999;
int dis[20050];
int u[20050],v[20050],w[20050];
int main()
{
 int n,m;
 while(scanf("%d %d", &n,&m)!=EOF)
 {
 	for(int i=1; i<=m; i++)
 	  scanf("%d %d %d", &u[i],&v[i],&w[i]);
 	for(int i=1; i<=n; i++)
 	   dis[i]=inf;
 	dis[1]=0;
 	for(int k=1; k<=n-1; k++)
 	   for(int i=1; i<=m; i++)
 	   {
 	   	 if(dis[v[i]]>dis[u[i]]+w[i])
 	   	   dis[v[i]]=dis[u[i]]+w[i];
 	   }
 	for(int i=1; i<=n; i++)
 	  printf("%d ", dis[i]);
 	  printf("\n");
 }
 return 0;
}

负权回路(回路权值之和为负)的判断
在核心语句后面加上一条判断就行

for(int k=1; k<=n-1; k++)
   	   for(int i=1; i<=m; i++)
   	   {
   	   	 if(dis[v[i]]>dis[u[i]]+w[i])
   	   	   dis[v[i]]=dis[u[i]]+w[i];
   	   }
   	   flag=0;
   	   for(int i=1; i<=m; i++)
   	   {
              if(dis[v[i]]>dis[u[i]]+w[i])
              flag=1;
              }
              if(flag==1)
              printf("有负权回路\n";

其他的代码和上面的一样把他套用进去就行,在这就不写出来了;

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

皮皮皮皮皮皮皮卡乒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值