迪杰斯特拉c++模板


最近要准备PAT的考试了,所以总结一下算法的模板什么的。并且规范一下自己的代码。

迪杰斯特拉c++模板

原理

原理我就不赘述了,大伙自行到别处看看,大概理解来说就是分为两个阵容。

第一个阵容设为u,第二个阵容设为v。//可以用visit[]来区别这两个阵容

每次将v中离节点最近的push入u,然后更新v中离节点的距离,用以下公式更新:
d i s t [ v i ] = d i s t [ u i ] + e [ u i ] [ v i ] dist[v_i]=dist[u_i]+e[u_i][v_i] dist[vi]=dist[ui]+e[ui][vi]
因为每次都是将距离最近的push进入u,所以可以保证不用更新u里面的数值。

作用

设一个源节点为v,可以求得每个节点离v最近的距离。

要使用的数据

#define MAX 999999    
visit[n]//用来判断是否访问,初始设置为0
e[n][n]//用来存储邻接矩阵,假如两个节点不相邻那么就设置其值为MAX
dist[n]//表示离v的距离,初始设值为MAX

代码模板

int e[][],dist[],visit[];
dist[c]=0;//这样可以保证从初始节点开始
while(1){
	int min=MAX,index=-1;
	for(int j=0;j<n;++j){
			if(dist[j]<min && !visit[j]) min=dist[j],index=j;//找到最小的
		}
	if(index==-1) break;//说明全部已经push进去,不连通的节点除外
	visit[index]=true;//将其值设置为真
	for(int j=0;j<n;++j){
	if(!visit[j] && e[index][j]!=MAX){
		if(dist[index]+e[index][j]<dist[j]) dist[j]=dist[index]+e[index][j];//更新值
		}
	}
}

关于最小路径(不是值)

类似于并查集的思想,即每次更新的时候给更新的点加一个爸爸。
可以用 p r e [ ] pre[] pre[]或者 f a t h e r [ ] father[] father[]来表示。可以放心的是因为每个值都是会被更新的不用担心有点不被更新到,除非是连通图外的点!

int e[][],dist[],visit[],father[];
dist[c]=0;//这样可以保证从初始节点开始
father[c]=0;
while(1){
	int min=MAX,index=-1;
	for(int j=0;j<n;++j){
			if(dist[j]<min && !visit[j]) min=dist[j],index=j;//找到最小的
		}
	if(index==-1) break;//说明全部已经push进去,不连通的节点除外
	visit[index]=true;//将其值设置为真
	for(int j=0;j<n;++j){
	if(!visit[j] && e[index][j]!=MAX){
		if(dist[index]+e[index][j]<dist[j]){
			dist[j]=dist[index]+e[index][j];//更新值
			father[j]=farher[index];//更新父节点
		}
		}
	}
}

1003 Emergency

PAT的一道题,写得挺乱的(指数据的定义方面)。这道题是迪杰斯特拉的应用,大概是让你求最小路径,并且再那么多相等的最小路径中你得算出其中点权最大的,path[]存人数(用w[]来定义好点),count[]存最小路径个数
然后同样是先初始源节点的值,然count是<时候更新,path是=时候更新。

  • 更新值:
  1. 如果是小于的情况
    最小距离更新,最小路径个数更新就是源的最小路径个数,即count[index]=count[j],人数就是源的人数加上该城市的人数
  2. 如果是等于的情况
    就是到这点有相同的最小距离了,所以最小路径的个数是原先的最小路径个数加上源的最小路径个数:count[j]+=count[index],然年最大人数进行比较更新。
#include <bits/stdc++.h>
#define MAX 999999
using namespace std;
int main()
{
	//迪杰斯特拉
	int num[500]={0};//每个城市的人数
	int matrix[500][500],dist[500],visit[500],count[500],path[500]; //path存人数。count存最小路径个数 
	int n,m,c1,c2,a,b,x; 
	cin>>n>>m>>c1>>c2;
	for(int i=0;i<n;++i) cin>>num[i];
	for(int i=0;i<n;++i) for(int j=0;j<n;++j){
		if(i==j) matrix[i][j]=0;
		else matrix[i][j]=MAX;
	}
	while(m--){
		cin>>a>>b>>x;
		matrix[a][b]=x;
		matrix[b][a]=x;
	} 
	for(int i=0;i<n;++i) dist[i]=MAX,visit[i]=0;
	path[c1]=num[c1];
	count[c1]=1;
    dist[c1]=0;
	while(1){
		int min=MAX;
		int index=-1;
		for(int j=0;j<n;++j){
			if(dist[j]<min && !visit[j]) min=dist[j],index=j;
		}//找到最小的
		if(index==-1) break;//没找到就break 
		visit[index]=true;
		for(int j=0;j<n;++j){
			if(!visit[j] && matrix[j][index]!=MAX){
				if(dist[index]+matrix[index][j]<dist[j]){
					dist[j]=dist[index]+matrix[index][j];
					count[j]=count[index];
					path[j]=path[index]+num[j];
				}
				else if(dist[index]+matrix[index][j]==dist[j]){
					count[j]=count[j]+count[index];
					if(path[index]+num[j]>path[j]) path[j]=path[index]+num[j];
				}
			}
		} 
	} 
	printf("%d %d",count[c2],path[c2]);

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值