贝尔曼福特算法

一、贝尔曼福特算法是在图中找各点距离顶点的最短路径,与Dijkstra不同的是,贝尔曼福特算法的边权可以为负数,而且贝尔曼福特算法除寻找最短路径之外还可以检测边权是否为负

二、①初始化图上所有点(除顶点外)到顶点的距离为无穷大(∞)顶点设为0

       ②最多进行n-1次操作(有可能更少),对各边进行松弛

          松弛解释:贝尔曼福特算法_第1张图片

                            如图已知从5到1有两条路径1->3->5或 1->3->4->5,然而1->3->5的长度为                              2+4=6,1->3->4->5的长度为2+1+2=5,1->3->4->5的长度较小,所以从5到1的最短距离为5

三、若要检测边权是否为负,只需遍历完之后,再遍历一遍,若顶点到节点的距离变为更小值,则边权存在负数

例题:

1378:最短路径(shopth)


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 7409     通过数: 3041

【题目描述】

给出一个有向图G=(V, E),和一个源点v0∈V,请写一个程序输出v0和图G中其它顶点的最短路径。只要所有的有向环权值和都是正的,我们就允许图的边有负值。顶点的标号从1到n(n为图G的顶点数)。

【输入】

第1行:一个正数n(2≤n≤80),表示图G的顶点总数。

第2行:一个整数,表示源点v0(v0∈V,v0可以是图G中任意一个顶点)。

第3至第n+2行,用一个邻接矩阵W给出了这个图。

【输出】

共包含n-1行,按照顶点编号从小到大的顺序,每行输出源点v0到一个顶点的最短距离。每行的具体格式参照样例。

【输入样例】

5
1
0 2 - - 10
- 0 3 - 7
- - 0 4 -
- - - 0 5
- - 6 - 0

【输出样例】

(1 -> 2) = 2
(1 -> 3) = 5
(1 -> 4) = 9
(1 -> 5) = 9

【提示】

样例所对应的图如下:

 

 这个题因为边权没有负数所以用贝尔曼福特算法 或Dijkstra算法都可以,但要注意这个图两点有方向,且输入要用到scanf的特点若输入一个字符,输入的返回值为1.之后就为贝尔曼福特算法

代码:

#include
using namespace std;
int n,z,v;
int dist[100009];
struct edge{
	int from;
	int to;
	int len; 
	edge(){}
	edge(int r,int d,int v){
		from=r;to=d;len=v;
	}
};
edge e1[100009];
int result=1;
bool gf(int sid){
	memset(dist,0x3f,sizeof(dist));
	dist[sid]=0;
	for(int i=1;i<=n-1;i++){
		bool bj=false;
		for(int j=1;j<=result;j++){
			edge e=e1[j];
			if(dist[e.from]!=0x3f3f3f3f&&dist[e.to]>dist[e.from]+e.len){
				dist[e.to]=dist[e.from]+e1[j].len;
				bj=true;
			}
		}
		if(!bj)return true;
	}
}
int main(){
	cin>>n>>v;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			if(scanf("%d",&z)){
			e1[result].from=i;
			e1[result].to=j;
			e1[result].len=z;
			result++;
			}
		}
	}
	gf(v);
	for(int i=1;i<=n;i++){
		if(dist[i]!=0x3f3f3f3f&&dist[i]!=0){
			cout<<"("<"<<" "<

例题二

1376:信使(msner)


时间限制: 1000 ms         内存限制: 65536 KB
提交数: 10721     通过数: 5390

【题目描述】

战争时期,前线有n个哨所,每个哨所可能会与其他若干个哨所之间有通信联系。信使负责在哨所之间传递信息,当然,这是要花费一定时间的(以天为单位)。指挥部设在第一个哨所。当指挥部下达一个命令后,指挥部就派出若干个信使向与指挥部相连的哨所送信。当一个哨所接到信后,这个哨所内的信使们也以同样的方式向其他哨所送信。直至所有n个哨所全部接到命令后,送信才算成功。因为准备充足,每个哨所内都安排了足够的信使(如果一个哨所与其他k个哨所有通信联系的话,这个哨所内至少会配备k个信使)。

现在总指挥请你编一个程序,计算出完成整个送信过程最短需要多少时间。

【输入】

第1行有两个整数n和m,中间用1个空格隔开,分别表示有n个哨所和m条通信线路,且1≤n≤100。

第2至m+1行:每行三个整数i、j、k,中间用1个空格隔开,表示第i个和第j个哨所之间存在通信线路,且这条线路要花费k天。

【输出】

一个整数,表示完成整个送信过程的最短时间。如果不是所有的哨所都能收到信,就输出-1。

【输入样例】

4 4
1 2 4
2 3 7
2 4 1
3 4 6

【输出样例】

11

这题也是贝尔曼福特算法 或Dijkstra算法都可以,在这用

贝尔曼福特算法,注意这题两点之间没有方向

代码:

#include
using namespace std;
int n,m,v,r,d,cnt=0;
int dist[1009];
struct edge{
	int from;
	int to;
	int len; 
	edge(){}
	edge(int r,int d,int v){
		from=r;to=d;len=v;
	}
};
edge e1[1009];
int result=1;
bool gf(int sid){
	memset(dist,0x3f,sizeof(dist));
	dist[sid]=0;
	for(int i=1;i<=n-1;i++){
		bool bj=false;
		for(int j=1;j<=2*result;j++){
			edge e=e1[j];
			if(dist[e.from]!=0x3f3f3f3f&&dist[e.to]>dist[e.from]+e.len){
				dist[e.to]=dist[e.from]+e1[j].len;
				bj=true;
			}
		}
		if(!bj)return true;
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>r>>d>>v;
		e1[result].from=r;
		e1[result].to=d;
		e1[result].len=v;
		e1[result+m].from=d;
		e1[result+m].to=r;
		e1[result+m].len=v;		
		result++;
	}
	gf(1);
	for(int i=1;i<=n;i++){
		cnt=max(cnt,dist[i]);
		if((dist[i]==0||dist[i]==0x3f3f3f3f)&&i!=1){
			cout<<-1;
			return 0;
		}
	}
	cout<

你可能感兴趣的:(算法,数据结构)