Dijkstra算法详解

一、Dijkstra算法(求单源最短路)

Dijkstra算法是贪心+广度优先搜索的最短路径算法

算法精髓:距离起点越近的点越先被扩展,可以保证所得的路径一定是最短路径

算法描述:

        1.初始化:起点到起点的最短距离为0,其他为无穷大,所有点标记为未扩展

        2.从未扩展的点中选择距离起点最近的点n标记为已扩展

        3.尝试将与n相连的节点到起点的距离更新为更短距离(松弛),若成功则将它放入备选队列

例如:

水从1开始,经过每段河道用1秒钟

初始化

当前点编号最短距离前节点
10
2
3
4
5

next

当前点编号最短距离前节点
10
231
371
445
531

finally 

当前点编号最短距离前节点
10
231
355
445
531

 二、例题1

1344:【例4-4】最小花费


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

【题目描述】

在n个人中,某些人的银行账号之间可以互相转账。这些人之间转账的手续费各不相同。给定这些人之间转账时需要从转账金额里扣除百分之几的手续费,请问A最少需要多少钱使得转账后B收到100元。

【输入】

第一行输入两个正整数n,m,分别表示总人数和可以互相转账的人的对数。

以下m行每行输入三个正整数x,y,z,表示标号为x的人和标号为y的人之间互相转账需要扣除z%的手续费 (z<100)。

最后一行输入两个正整数A,B。数据保证A与B之间可以直接或间接地转账。

【输出】

输出A使得B到账100元最少需要的总费用。精确到小数点后8位。

【输入样例】

3 3
1 2 1
2 3 2
1 3 3
1 3

【输出样例】

103.07153164

【提示】

【数据规模】

1<=n<=2000

 分析:构建一个图,以人为点,手续费为边,求A到B的最短距离(注意:数组用double,计算时要用乘法,不要用加法)

代码实现

#include<bits/stdc++.h>
using namespace std;
bool flag[2009];
int A,B,n,m,x,y,z;
double a[2009][2009],dist[2009];
void Dijkstra(int s, int d){
	for(int i=1; i<=n; i++){
		dist[i]=a[s][i];
		flag[i]=false;
	} 
	dist[s]=0;
	flag[s]=true;
	for(int i=1;i<=n;i++){
		double maxv=0.0;
		int x=d;
		for(int j=1;j<=n;j++){
			if(!flag[j]&&dist[j]>maxv){
				maxv=dist[j];
				x=j;
			}
		}
		if(x==d)
			return;
		flag[x]=true;
		for(int j=1; j<=n;j++){
			if(!flag[j]&&a[x][j]>0){
				if(dist[x]*a[x][j]>dist[j]){
					dist[j]=dist[x]*a[x][j];
				}
			}
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>x>>y>>z;
	 	a[x][y]=a[y][x]=0.01*(100-z);
	}
	cin>>A>>B;
	Dijkstra(A,B);
	printf("%.8lf",100/dist[B]);
	return 0;
}

三、例题2 

1376:信使(msner)


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

【题目描述】

战争时期,前线有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

分析: 构建一个图,所有边设为无穷大,再输入,求一遍从指挥部到任意一个哨所的最短路
最后求出指挥部到任意哨所的最远距离即为答案

代码实现

#include<bits/stdc++.h>
using namespace std;
bool flag[2009];
int A,B,n,m,x,y,z;
int v[2009][2009],dis[2009],k,a[1009],minv,maxv=-1;
void Dijkstra(){
	for(int i=1;i<=n;i++){
		dis[i]=v[1][i];
	}
    a[1]=0;
	dis[1]=0;
    for(int i=1;i<n;i++){
        minv=INT_MAX;
        for(int j=1;j<=n;j++){
            if(a[j]==0&&dis[j]<minv){
                k=j;
                minv=dis[j];
            }
        }
        a[k]=1;
        for(int j=1;j<=n;j++){
            if(dis[j]>dis[k]+v[k][j]&&v[k][j]<INT_MAX)
            dis[j]=dis[k]+v[k][j];
        }
    }
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			v[i][j]=INT_MAX;
			dis[i]=INT_MAX;
		}
	}
	for(int i=1;i<=m;i++){
		cin>>x>>y>>z;
	 	v[x][y]=v[y][x]=z;
	}
	Dijkstra();
	for(int i=1;i<=n;i++){
		maxv=max(maxv,dis[i]);
	}
	if(maxv>=INT_MAX){
		cout<<"-1";
	} else{
		printf("%d",maxv);
	}
	return 0;
}

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值