Bellman-Ford算法~~~~~
Bellman-Ford算法描述:
1,.初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0;
2.迭代求解:反复对边集E中的每条边进行
松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次)
3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。
描述性证明:
首先指出,图的任意一条
最短路径既不能包含负权回路,也不会包含正权回路,因此它最多包含|v|-1条边。
其次,从源点s可达的所有顶点如果 存在
最短路径,则这些最短路径构成一个以s为根的最短路径树。Bellman-Ford算法的
迭代
松弛操作,实际上就是按顶点距离s的层次,逐层生成这棵
最短路径树的过程。
在对每条边进行1遍
松弛的时候,生成了从s出发,层次至多为1的那些树枝。也就是说,找到了与s至多有1条边相联的那些顶点的
最短路径;对每条边进行第2遍
松弛的时候,生成了第2层次的树枝,就是说找到了经过2条边相连的那些顶点的最短路径……。因为
最短路径最多只包含|v|-1 条边,所以,只需要循环|v|-1 次。
每实施一次
松弛操作,
最短路径树上就会有一层顶点达到其最短距离,此后这层顶点的最短距离值就会一直保持不变,不再受后续松弛操作的影响。(但是,每次还要判断
松弛,这里浪费了大量的时间,怎么
优化?单纯的优化是否可行?)
注意:上述只对正权图有效。如果存在负权不一定第i次就能确定最短路,且与边的顺序有关。
#include<stdio.h>
#include<string.h>
struct bank
{
int u,v;
double arb,ayb;
}bank[301];
int i,j;
int flag,a,b;
double ar,ay,br,by;
double mmax[301];
int bellman(int N,int M,double mmax[])
{
for(i=1;i<=N-1;i++)
{flag=0;
for(j=1;j<=2*M;j++)
{
if((mmax[bank[j].u]-bank[j].ayb)*bank[j].arb>0&&(mmax[bank[j].u]-bank[j].ayb)*bank[j].arb>mmax[bank[j].v])
{
mmax[bank[j].v]=(mmax[bank[j].u]-bank[j].ayb)*bank[j].arb;
flag=1;
}
// if(mmax[S]>V)break;
}
if(flag==0)break;
}
for(j=1;j<=2*M;j++)
if((mmax[bank[j].u]-bank[j].ayb)*bank[j].arb>mmax[bank[j].v])
return 1;
return 0;
}
int main()
{
int mm;
int N,M,S;
double V;
scanf("%d%d%d",&N,&M,&S);
scanf("%lf",&V);
for(i=1;i<=2*M;i++)
{
scanf("%d%d",&a,&b);
scanf("%lf%lf%lf%lf",&ar,&ay,&br,&by);
bank[i].u=a;
bank[i].v=b;
bank[i].arb=ar;
bank[i].ayb=ay;
i++;
bank[i].u=b;
bank[i].v=a;
bank[i].arb=br;
bank[i].ayb=by;
}
memset(mmax,0,sizeof(mmax));
mmax[S]=V;
mm=bellman(N,M,mmax);
if(mm)
printf("YES\n");
else
printf("NO\n");
return 0;
}