蓝桥杯刷题——最短路(迪杰斯特拉算法)

270 阅读2分钟

「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。

这是蓝桥杯19年省赛的一道填空题,答案其实自己看一下题目就能得出来了,甚至不需要去设计什么算法,但如果题目真的要出复杂一点,用肉眼去看是得不到答案了,这道题就是一个经典的迪杰斯特拉算法题目,数据结构中应有学过。

题目

image.png

思路

看到求单源最短路径的题目,我们应当是能够想到用迪杰斯特拉算法来解决的。能想到这个算法,然后脑海里能够清晰的复现出这个算法流程,这道题目应该就能够做出来了。无向图,我们肯定是要先构建出无向图的,用一个二维数组来存储就可以了,哪个节点到哪个节点就可以作为索引了,而它们之间的值就是他们的在无向图中的长度了。构建好无向图,就开始设计迪杰斯特拉算法了。

迪杰斯特拉算法

大致说明一下迪杰斯特拉算法,这个算法有点像是贪心算法,都是找到当前最好的一个情况,再接着往下做。我们将给定的节点分为两组,一组是已经找到从源点开始到这个点的最短路径,为s组,另一组是还没有找到的,为f组。当f组中的所有节点都放到s组中时,算法也就结束了。而一开始,很显然,s组中只有源点这一个点在,这里的最短路径就设为0。第二个点就按索引的顺序来好了,第二个点是可以随机选取的。每次最短路径还要再进行一个判断就是:

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

这里n就是n个节点,dist是源点到这个节点的最短路径,g存储的是无向图中的值哦。每次选取节点都要选取最短路径的。代码如下:

int t=-1;//要选取的节点 
for(int j=1;j<=n;j++) { 
if(!vis[j]&&(t==-1||dist[j]<dist[t]))//要最短并且没有被选过的 
t=j; 
}
vis[t]=1;//选了之后要设置为1代表已经选过。

总代码

#include <bits/stdc++.h>
using namespace std;
const int N=21,n=19;//共19个字母
int dist[N];
int g[N][N];
void add(int x,int y,int c)
{
  g[x][y]=g[x][y]=c;
}
int vis[N];
int diskt()
{
  memset(dist,27,sizeof dist);
  dist[1]=0;
  for(int i=0;i<n;i++)
  {
    int t=-1;
    for(int j=1;j<=n;j++)
    {
      if(!vis[j]&&(t==-1||dist[j]<dist[t]))
        t=j;
    }
    vis[t]=1;

    for(int j=1;j<=n;j++)
    {
      dist[j]=min(dist[j],dist[t]+g[t][j]);
    }
  }
  return dist[n];
}
int main()
{
    memset(g,27,sizeof(g));
	for(int i=1;i<=19;i++){
		int x,y,z;
		cin>>x>>y>>z;
		add(x,y,z);
	} 
    cout<<diskt();
  return 0;
}