Luck_ZY will AK IOI(口号,勿在意)
发一篇小小的博客,关于新学的Dijkstra算法。
本蒟蒻一直喜欢用暴力而简单的Floyd算法,但是作为一个基础算法,Dijkstra算法还是必须要会的
算法用途
Dijkstra算法是用来处理最短路径问题
主要寻找从某一起点到其余所有的点的最短路径
算法实现
Dijkstra算法主要用贪心算法,先存下起点到每一个点的距离,对于与起点不联通的点,到起点的距离记为正无穷,之后进行松弛操作,及在有中间点进行中转后,到起点的距离要更近,更新到该点的最小距离
对于这样一个有向图,如果以0为起点,所求的为其他所有点到0点的最短距离
若设置一个数组来储存每一个点到0的距离
设INF为一个无穷大的数
设 dis[].
数组dis[i]表示点i到起点的距离
dis[i]={0,1,12,INF,INF,INF}
之后对于点3,由于通过点1中转的路径小于INF,所以dis[3]=4
以此类推,dis[2]=8,dis[3]=4,dis[4]=13,dis[5]=17
代码实现:
1.存图
很简单,一般存图都会选用二维数组or邻接表or邻接矩阵
最直接的方法二维数组:
a[u][v];//表示从u指向v的一条边
我就直接上代码了
我这个人没别的优点,就是写代码时喜欢写注释,一些dalao可能会觉得啰嗦,但我还是写了
#include<bits/stdc++.h>
#define M 10005//M 表示最大的点数
using namespace std;
const int N=1e9+7;//初始时赋值的最大值
int n,m,s;//n储存点数,m储存边,s储存start
int a[M][M];//用来储存有向边
bool vis[M]={false};//被用来储存点是否被查看过
int dis[M];//储存起点到每个点的最短路
/*
将a数组的每一个点的权值都设置成正无穷
在储存边u->v的权值w时,储存a[u][v]的值为w
将dis数组初始值also设置成正无穷
*/
void Dijkstra(int s){//s为起点
//Dijkstra函数的作用就是求所有的点到起点的最小值
fill(dis,dis+M,N);//将dis数组的值赋为最大值
dis[s]=0;//以s到s的最小距离为0
for(int i=1;i<=n;i++)
/*
进行n次循环。
由于总共有n个点,故n次循环,就可以对每一个点进行访问
每一次访问,都要对所有值进行更新
*/
{
int u=-1;//u用来表示到s最小值的点
int MIN=N;
for(int j=1;j<=n;j++)
{
if(vis[j]==false&&dis[j]<MIN)
//条件(点j没有被访问过&&s->j有边&&s到点j的距离小于MIN)
{
u=j;//到s最小的为点j,将j更新到u
MIN=dis[j];//更新最小值min
}
}
if(u==-1) return;//如果u的值为-1,说明没有与s联通的边
vis[u]=true;//u has been 访问过
for(int k=1;k<=n;k++){
//寻找与u相连的边
if(vis[k]==false&&a[u][k]!=N)
//k点没有被访问过&&存在u到点k的边
{
if(dis[u]+a[u][k]<dis[k])
//以点u为中介的情况更优
{
dis[k]=dis[u]+a[u][k];
}
}
}
}
}
int main (){
ios::sync_with_stdio(false);
cin>>n>>m>>s;
fill(a[0],a[0]+M*M,N);
for(int i=1;i<=m;i++){
int u,v,w;
cin>>u>>v>>w;
a[u][v]=w;
}
Dijkstra(s);//begin
for(int i=1;i<=n;i++){
cout<<dis[i]<<' ';
}
return 0;
}
。。。
问题
这个代码你会发现编译.运行&样例都能过
But MLE or RE
要不就是数组太大要不就开太小
太多的空间被浪费
于是就需要学习一个新东西,叫做链式向前星
我解释不清
直接上代码吧
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<memory.h>
#define MAXN 1000010
using namespace std;
const int INF=1e9+77;
int n;//point
int m;//edge
int start;//source point
int dis[MAXN];//best way
bool visit[MAXN];//whether visited
typedef struct Edge{
int next;//next edge with the same head[]
int to;//next point
int w;//len
}Edge;
Edge edge[MAXN];
int head[MAXN];
int tot;
void init()
{
memset(dis,INF,sizeof(dis));
memset(visit,false,sizeof(visit));
memset(head,-1,sizeof(head));
tot=0;
}
void add(int u,int v,int wi)
{
edge[tot].to =v;
edge[tot].w =wi;
edge[tot].next =head[u];
head[u]=tot++;
}
void dijkstra(int s){
int min,pos;
while(1){
min=INF;
pos=-1;
for(int i=1;i<=n;i++)
{
if(!visit[i]&&min>dis[i])
{
min=dis[i];
pos=i;
}
}
if(pos==-1)
{
break;
}
visit[pos]=true;
for(int i=head[pos];i!=-1;i=edge[i].next )
{
int t=edge[i].to ;
if(!visit[t]&&dis[t]>(dis[pos]+edge[i].w ))
{
dis[t]=dis[pos]+edge[i].w ;
}
}
}
return;
}
int main()
{
init();
scanf("%d%d%d",&n,&m,&start);
dis[start]=0;
for(int i=1;i<=m;i++)
{
int u,v,wi;
scanf("%d%d%d",&u,&v,&wi);
add(u,v,wi);
// add(v,u,wi);
}
dijkstra(start);
for(int i=1;i<=n;i++)
{
cout<<dis[i]<<' ';
}
return 0;
}