Dijkstra算法(蓝桥杯省赛真题)

今天为大家介绍一下Dijkstra算法及其模板,并且解决蓝桥杯省赛出现的真题——路径 Dijkstra算法
⭐Dijkstra算法的基本思想是:每次找到里源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到雨点到其余所有点的最短路径。(dist[i]数组代表从源点到顶点i的最短路,st[i]用来标记该点是否已经被更新)
⭐基本步骤如下:
⭐1.将所有的顶点分为两部分:已知最短路程的顶点集合P和未知最短路径的顶点集合Q。最开始,已知最短路径的顶点集合P中只有源点一个顶点。我们这里用一个bool类型数组st[]来记录哪些点在集合P中。例如对于某个顶点i,如果st[i]为true则表示这个顶点在集合P中,如果st[i]为false则表示这个顶点在集合Q中。
⭐2.设置源点s到自己的最短路径为0即dist[1]=0, 若存在有源点能直接到达的项点1。则把dist[i]设为e[s][i]同时把所有其他(源点不能直接到达的)顶点的最短路径设为∞。
⭐3.在集合Q中的所有顶点中选择一个离源点s最近的顶点u(即dist[u]最小) 加入到集合P。并考察所有以点u为起点的边,对每一条边进行松弛操作。例如存在从u到v的一条边有dist[v]>dist[u]+e[u][v](即从源点直接到v的距离大于从源点先到u再从u到v的距离),我们可以用新值dist[u]+e[u][v]来替代当前dist[v]中的值。
⭐4.重复第3步,如果集合Q为空,算法结束。最终dist数组中的值就是源点到所有顶点的最短路径。

代码模板如下:

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int g[N][N];//用来存边
int dist[N];//记录每个点到源点的距离
bool st[N];//标记该点是否已更新
int n,m;
int pirm()
{
    
    
    memset(dist,0x3f,sizeof dist);
    dist[1]=0;

    for(int i=0;i<n;i++)
    {
    
    
        int t=-1;
        for(int j=1;j<=n;j++)
       		if(!st[i]&&(t==-1||dist[t]>dist[j]))
        			t=j;

    st[t]=true;

    for(int j=1;j<=n;j++)
        dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
    return dist[n];
}

int main()
{
    
    
    scanf("%d%d",&n,&m);
    memset(g,0x3f,sizeof g);
    for(int i=1;i<=m;i++)
    {
    
    
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        g[a][b]=min(g[a][b],c);
    }

    int t=dijkstra();
    printf("%d\n",t);
}
下面是2021年蓝桥杯省赛真题就是用到了Dijkstra算法,这题写起来非常简单就是一道模板题,只不过中间还穿插了一些最大公约数和最小公倍数的知识,题目和Ac代码如下,这题就留给读者你们自己思考啦!!!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll e[2050][2050],dist[2050];
bool st[2050];

ll gcd(ll a,ll b)//求公约数
{
    
    
	return a%b==0?b:gcd(b,a%b);
}

ll lcm(ll a,ll b)//求最小公倍数
{
    
    
	return a*b/(gcd(a,b));
}

int dijkstra()//Dijkstra算法
{
    
    
	memset(dist,0x3f,sizeof dist);
	dist[1]=0;
	for(int i=1;i<=2021;i++)
	{
    
    
		int t=-1;
		if(!st[i]&&(t==-1||dist[t]>dist[i]))
		t=i;
		st[t]=true;
		for(int j=1;j<=2021;j++)
		dist[j]=min(dist[j],dist[t]+e[t][j]);
	}
	return dist[2021];
}

int main()
{
    
    
	memset(e,0x3f,sizeof e);
	for(int i=1;i<=2021;i++)
	{
    
    
		for(int j=i;j<=2021;j++)
		{
    
    
			int k=j-i;
			if(k>21)break;
			else 
			{
    
    
				e[i][j]=e[j][i]=lcm(i,j);
			}
		}
	}
	int ans=dijkstra();
	cout<<ans<<endl;
} 

猜你喜欢

转载自blog.csdn.net/Stephen_Curry___/article/details/124042365