1860Currency Exchange

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次就能确定最短路,且与边的顺序有关。
如果没有负权回路,由于 最短路径树的高度最多只能是|v|-1,所以最多经过|v|-1遍 松弛操作后,所有从s可达的顶点必将求出最短距离。如果 d[v]仍保持 +∞,则表明从s到v不可达。
如果有负权回路,那么第 |v| 遍 松弛操作仍然会成功,这时,负权回路上的顶点不会收敛。 [1]
#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;
}



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值