bellman-ford算法解析
1.定义以及复杂度比较
bellman-ford,顾名思义,是一个名叫bellman·ford的人发明的,它主要用于求单源最短路,也就是说他和Dijkstra差不多......
但是!!它比Dijkstra更简单!!
而且由于bellman-ford的时间复杂度是O(mn)
Djkstra的复杂度是O(n^2)
所以在m<n时,也就是稀疏图时,它是要比Dijkstra要快的!(在都不优化的情况下)
BUT!!
bellman-ford能判断负环!
说了那么多,bellman-ford到底什么思想呢?
2.算法解析
我们假设现在有一个城市,有许多的路口,某些路口有道路相连,每个路口有警察值班
现在来了一位游客,他想知道任意一个路口到路口s的距离
我们先让一位警察问问与自己相连路口的警察:从你那里能到s吗?有多远?
如果那个警察知道,那么一定是他与s相连,或者之前已经知道了自己与s的距离
如果他也不知道,那就让他再问问与自己相连路口的警察
......
一直这样下去,总有至少一个警察会问到s路口的警察,他便会把答案一层层返回过去,并且加上两个路口的距离
返回结束,所有人都会知道自己与s的距离
看一下这样计算的复杂度,首先游客一定要在所有路口都问一遍距离 n次
对于每次询问,警察要问一遍所有的道路,m次
所以复杂度是O(mn)
接下来就是代码实现啦
#include<bits/stdc++.h> using namespace std; struct edge { int u,v,w; }e[10005]; int n,m,cnt; int p[105]; void print(int s,int t) { if(s==t) { printf("%d",s); return ; } print(s,p[t]); printf("%d",t); } void bellman() { int s=1; int d[105]; for(int i=1;i<=n;i++) { d[i]=1000000; } d[s]=0; for(int k=1;k<=n;k++) { for(int i=0;i<=cnt;i++) { int x=e[i].u,y=e[i].v; if(d[x]>d[y]+e[i].w) { d[x]=d[y]+e[i].w; p[x]=y; } } printf("%d\n",d[n]); //print(s,n); } } int main() { while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) return 0; cnt=0; while(m--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); e[cnt].u=a; e[cnt].v=b; e[cnt].w=c; cnt++; e[cnt].u=b; e[cnt].v=a; e[cnt].w=c; cnt++; } bellman(); } return 0; }
(可以结合hdu2544看一看)
当然,如果你足够了解bellman-ford的功能,你就会发现,这段代码没有判断负环的功能
不能判断负环的bellman和Dijkstra有什么区别(bushi)
那么下来我们来想一想怎么判断负环
我们已经知道bellman在经过n次松弛后,一定能求出每个点到s的最短路径
但是如果存在负环的话,那每一圈的松弛都会让这个点的权值更少一点,因此无法结束
所以,我们只用判断操作次数是否比n大,就可以判断是否有负环了
代码如下(只改了函数部分)
#include<bits/stdc++.h> using namespace std; struct edge { int u,v,w; }e[10005]; int n,m,cnt; int p[105]; /*void print(int s,int t) { if(s==t) { printf("%d",s); return ; } print(s,p[t]); printf("%d",t); }*/ void bellman() { int s=1; int d[105]; for(int i=1;i<=n;i++) { d[i]=1000000; } d[1]=0; int k=0; bool flag=true; while(flag) { k++; flag=false; if(k>n) { cout<<"有负圈"; return ; } for(int i=0;i<=cnt;i++) { int x=e[i].u,y=e[i].v; if(d[x]>d[y]+e[i].w) { d[x]=d[y]+e[i].w; flag=true; } } } printf("%d\n",d[n]); //print(s,n); } int main() { while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) return 0; cnt=0; while(m--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); e[cnt].u=a; e[cnt].v=b; e[cnt].w=c; cnt++; e[cnt].u=b; e[cnt].v=a; e[cnt].w=c; cnt++; } bellman(); } return 0; }
图论,从入门到放弃......