Bellman_ford算法:也是求单源最短路径,它与Dijkstra算法的区别是,它可以检查是否有负权值边的存在;如果有负权值边的话,是不存在最短路径的,因为一个数+负数,一定会更小,所以dis数组会不断更新;
#include<cstdio>
#include<iostream>
using namespace std;
#define INF 9999999
struct node
{
int u,v,w;
};//用结构体来保存边,u,v,w分别为边的端点和权值
struct node a[109];
int n,m,dis[109],t;//n个点,m条边,dis[i]保存的是源点s到i的最短路径
bool bellman_ford(int s)//源点s
{
int i,j;
bool flag = true;//bool型变量,用来判断是否有负权值的边
dis[s] = 0;//源点到源点的距离为0,这条语句非常的关键,就是因为它,下面的
//dis数组才会更新
for (i = 1; i <= n-1; ++i)//最坏的情况,内层for循环,假设每次循环完只会更新
//一条边,那么n个点,源点到其他点最多需要n-1条边,所以循环n-1次就OK
{
for (j = 1; j <= 2*m; ++j)//m条边,因为是无向图,所以是2m
{
if (dis[a[j].u] > dis[a[j].v] + a[j].w)//正是因为dis[s]=0,dis数组才会更新
dis[a[j].u] = dis[a[j].v] + a[j].w;
}
}
for (j = 1; j <= 2*m; ++j)
{
if (dis[a[j].u] > dis[a[j].v] + a[j].w)//原来的最短路径+负数,一定会更小,也就是说,如果
//会更新,那么说明有负权值的边存在
{
flag = false;
break;
}
}
return flag;
}
int main()
{
int i,j,s,d,u,v,w;
while (~scanf("%d%d",&n,&m))
{
for (i = 1; i <= n; ++i)
dis[i] = INF;
j = 1;
t = m;
while (t--)
{
scanf("%d%d%d",&u,&v,&w);
a[j].u = u;
a[j].v = v;
a[j++].w = w;
a[j].u = v;
a[j].v = u;
a[j++].w = w;
}//因为是无向图,边正反存
scanf("%d%d",&s,&d);//s是源点,d是终点
if (bellman_ford(s))
printf("%d\n",dis[d]);
else
printf("sorry\n");
}
return 0;
}
/*
该算法是从边出发的!边更新了,也就是到点的距离更新了,然后感觉也是用点来更新点的
给两组样例吧
(1) (2)
5 7 4 4
1 2 100 1 2 -9
1 5 10 2 3 1
1 3 30 3 4 2
2 3 60 4 1 3
2 4 10 1 2
3 4 60 (sorry)
4 5 50
1 4
(60)
根据样例画画图就很好理解!
*/