Bellman_Ford —–最短路
情景带入:给你两个数 m,n。n代表一共有n个村庄,之后有m行,每行包含三个数 from,to,dist.这三个数代表着,从村庄from到村庄to有dist 这么长的距离,两个村庄之间可能有神奇的漩涡而导致他们之间的路径为负数。,此为无向图。
现在想知道从村庄1到任意村庄的最短的路径是多少。
可以想象,从村1到村n如果存在最短路,那么这个最短路之间的村庄数肯定是小于等于 n-1 的(包含村n),那么可以对输入的这m组数据关系,进行n-1次优化操作,那么得到的结果肯定就是最优的.
附代码:
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string.h>
using namespace std;
const int inf=0x3f3f3f3f;
int main()
{
int m,n;
while(~scanf("%d%d",&m,&n))
{
int dist[n+3],fro[m+3],to[m+3],w[m+3];
memset(dist,inf,sizeof(dist));
dist[1]=0;
for(int i=0; i<m; i++)
scanf("%d%d%d",&fro[i],&to[i],&w[i]);
for(int i=0; i<n-1; i++)
for(int j=0; j<m; j++)
{
int x=fro[j],y=to[j];
/*优化操作,与floyd相似,因为是无向图,所以需要用dist[x]
来优化dist[y],并用dist[y]来优化dist[x]*/
if(dist[x]<inf)
dist[y]=min(dist[y],dist[x]+w[j]);
if(dist[y]<inf)
dist[x]=min(dist[x],dist[y]+w[j]);
}
printf("%d\n",dist[n]);
}
}
题目链接:http://poj.org/problem?id=2387
此问题与http://blog.csdn.net/stffer/article/details/46834343的问题背景一样,可参考.
由于还没做到合适的题目,所以就拿一个没有负数的最短路题目凑数了,但是bellman_frod是可以解决某些路径为负的最短路问题的,他们之间的最短路问题的.dijkstra不能解决是因为如果有负数存在,dijkstra算法每次都可以通过这个负数来更新出一个比之前数值更小的dist[]数组.于是就成了死循环了.而 bellman_frod 只执行(n-1)*m次优化操作.由于不存在负权,上述代码中也就没有判断是否存在负权回路
如有负权,应加上如下代码:
int flog==1;
for(int i=0;i<m;i++)
{
//不可能发生的情况,因为如果有最短路,那么最坏的结果也应该是
//dist[fro[i]]>dist[to[i]]+w[i] 或 dist[to[i]]>dist[fro[i]]+w[i]
if(dist[fro[i]]>dist[to[i]]+w[i])
{
flog=0;
break;
}
if(dist[to[i]]>dist[fro[i]]+w[i])
{
flog=0;
break;
}
}
if(flog==1) //无负权回路,即存在最短路
else //有负权回路
说到bellman_frod 不得不说一下 SPFA,即用队列对现在的这一算法进行优化,思想还是不变的.
附代码:
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<iostream>
#include<string.h>
using namespace std;
const int inf=0x3f3f3f3f;
struct edge
{
int to,w;
edge(int to1=0,int w1=0):to(to1),w(w1) {}
};
vector<edge> G[10000];
void into(int fro,int to,int w)
{
//无向图
G[fro].push_back(edge(to,w));
G[to].push_back(edge(fro,w));
}
int main()
{
int m,n;
while(~scanf("%d%d",&m,&n))
{
int dist[n+3],fro[m+2],to[m+2],w[m+2];
int vist[n+3],cnt[n+3];
queue<int>q;
memset(vist,0,sizeof(vist));
memset(cnt,0,sizeof(cnt));
memset(dist,inf,sizeof(dist));
dist[1]=0;
vist[1]=1;
for(int i=0; i<m; i++)
scanf("%d%d%d",&fro[i],&to[i],&w[i]);
for(int i=0; i<m; i++) //初始化
into(fro[i],to[i],w[i]);
q.push(1);
int flog=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vist[u]=0;
for(int i=0; i<G[u].size();i++)
{
edge &ff=G[u][i];
if(dist[u]<inf&&dist[ff.to]>dist[u]+ff.w)
{
dist[ff.to]=dist[u]+ff.w;
if(vist[ff.to]==0)
{
q.push(ff.to);
vist[ff.to]=true;
if(++cnt[ff.to]>n)
{
flog=1;
break;
}
}
}
}
}
if(flog!=1) //存在最短路
printf("%d\n",dist[n]);
}
}