单源最短路劲(朴素dijkstra模板 + 邻接表实现 + 堆优化 +无向图+ 有向图)不定时更新

本文深入解析Dijkstra算法,回顾作者从初学到熟练的过程,分享了邻接矩阵和邻接表两种实现方式,以及堆优化技巧。文章通过具体代码示例,详细解释了算法的每一步操作,适合所有对图论和最短路径算法感兴趣的学习者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 刚复习完floyd,开始复习dijkstra,大二那会学过一波不是很懂,dp做的多了发现真的就简单233,反正我只是一个会裸题的弱鸡

不定时更新dijkstra的模板比如邻接表和堆优化的dijkstra,马上省赛了也不知道会不会出图论,希望出来我能秒ac233.对应的意思模板代码里我都注释了看代码就好。

# include <iostream>
# include <numeric>
# include <algorithm>
# include <functional>
# include <list>
# include <map>
# include <set>
# include <stack>
# include <deque>
# include <queue>
# include <vector>
# include <ctime>
# include <cstdlib>
# include <cmath>
# include <string>
#include <cstring>
#include<cstdio>

using namespace std;
#define ll long long int
const int inf = 0x3f3f3f3f;
const int maxn = 1e2 + 10;
int book[maxn][maxn];
int dis[maxn];
bool flag[maxn];

void fun()
{
    for(int i = 0; i < maxn; i++)
    {
        for(int j = 0; j < maxn; j++)
        {
            if(i == j)
            {
                book[i][j] = 0;
            }
            else
                book[i][j] = inf;
        }
    }
}
int main(int argc, char  *argv[])
{
    int n, m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        fun();
        //读入边
        for(int i = 1; i <= m; i++)
        {
            int x, y, len;
            scanf("%d%d%d", &x, &y,&len);
            if(len < book[x][y])
            {
                book[x][y] = len;
            }
        }
        //初始化源点的路程,表示源点到各个点的距离这里用1来当源点
        for(int i = 1; i<=n; i++)
        {
            dis[i] = book[1][i];
        }
        //初始化标记路程
        memset(flag, false, sizeof(flag));
        //源点标记为1
        flag[1] = true;
        //dijkstra
        //当前点有1个初始化点所以执行n-1次就可以
        for(int i = 1; i <= n -1; i++)
        {
            //首先找到距离源点最近的点
            int minn = inf;
            int k = -1;
            for(int j = 1; j <= n; j++)
            {
                if(minn > dis[j] && !flag[j])
                {
                    minn = dis[j];
                    k = j;
                }
            }

            if(k != -1)
            {
                flag[k] = true;
                //表示当前源点到j的距离能不能被源点到k + book[k][j]中转松弛
                for(int j = 1; j <= n; j++)
                {
                    if(book[k][j] < inf)
                    {
                        if(dis[j] > dis[k] + book[k][j])
                        {
                            dis[j] = dis[k] + book[k][j];
                        }
                    }
                }
            }
        }
        for(int i = 1; i <= n; i++)
        {
            printf("%d ", dis[i]);
        }
        printf("\n");
    }
	return 0;
}
# if 0
测试数据:
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4

0 1 8 4 13 17
#endif

邻接表实现的dijkstra 

# include <iostream>
# include <numeric>
# include <algorithm>
# include <functional>
# include <list>
# include <map>
# include <set>
# include <stack>
# include <deque>
# include <queue>
# include <vector>
# include <ctime>
# include <cstdlib>
# include <cmath>
# include <string>
# include <cstring>
# include <iomanip>

using namespace std;
# define ll long long int
const int maxn = (7e3 + 5)* 2;
const int inf = 0x3f3f3f3f;
int first[maxn];
int ne[maxn];
int u[maxn], v[maxn], w[maxn], dis[maxn], flag[maxn];
int f[maxn];//记录路径
int n, m, s, t;//s,t是起始点
void fun1()
{
    memset(first, -1, sizeof(first));
    memset(ne, -1, sizeof(ne));
}
void fun2()
{
    memset(f, false, sizeof(f));
    memset(dis, inf, sizeof(dis));
    memset(flag, false, sizeof(flag));
}
void read()
{
     for(int i = 1; i <= m; i++)
    {
        cin >> u[i] >> v[i] >> w[i];
        ne[i] = first[u[i]];
        first[u[i]] = i;
    }
    //双向路劲
    for(int i = m + 1; i <= m * 2; i++)
    {
        u[i] = v[i - m];
        v[i] = u[i - m];
        w[i] = w[i - m];
        ne[i] = first[u[i]];
        first[u[i]] = i;
    }

}
void dijkstra()
{
    fun2();
    dis[s] = 0;
    for(int i = 1; i <= n; i++)
    {
        int minn = inf;
        int k = -1;
        for(int j = 1; j <= n; j++)
        {
            if(dis[j] < minn && !flag[j])
            {
                minn = dis[j];
                k = j;
            }
        }
        if(minn == inf)
            break;
        flag[k] = true;
        for(int j = first[k]; j != -1; j= ne[j])
        {
            if(dis[v[j]] > dis[k] + w[j])
            {
                dis[v[j]] = dis[k] + w[j];
                f[v[j]] = k;//存松弛的路径
            }
        }
    }
    cout << dis[t] << endl;
    return ;
}
void dfs(int x)//打印路径
{
    cout << x << endl;
    if(f[x] == 0)
        return ;
    else
    {
        dfs(f[x]);
        if(x == n)
            cout << f[x] << endl;
        else
            cout << f[x] << " ";
    }
}
int main(int argc, char *argv[])
{
    ios_base::sync_with_stdio(false);
    std::cin.tie(false);

    while(cin >> n >> m >> s >> t)
    {
        fun1();
        read();
        dijkstra();
        dfs(n);
    }
    return 0;
}

 

//堆优化

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
#define in(a) a=read()
#define REP(i,k,n) for(long long i=k;i<=n;i++)
#define MAXN 10010
using namespace std;
typedef pair<long long,long long> P;
inline long long read(){
    long long x=0,t=1,c;
    while(!isdigit(c=getchar())) if(c=='-') t=-1;
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
    return x*t;
}
long long n,m,s;
long long total=0,head[MAXN],nxt[MAXN<<10],to[MAXN<<10],val[MAXN<<10];
long long dis[MAXN],vis[MAXN];
priority_queue <P, vector<P>,greater<P> > Q;//优先队列优化
inline void adl(long long a,long long b,long long c){
    total++;
    to[total]=b;
    val[total]=c;
    nxt[total]=head[a];
    head[a]=total;
    return ;
}
inline void Dijkstra(){
    REP(i,1,n)  dis[i]=2147483647;
    dis[s]=0;
    Q.push(P(0,s));
    while(!Q.empty()){
        long long u=Q.top().second;//取出dis最小的点
        Q.pop();//弹出
        if(vis[u])  continue;
        vis[u]=1;
        for(long long e=head[u];e;e=nxt[e])
            if(dis[to[e]]>dis[u]+val[e]){
                dis[to[e]]=dis[u]+val[e];
                Q.push(P(dis[to[e]],to[e]));//插入
            }
    }
    return ;
}
int main(){
    in(n),in(m),in(s);
    long long a,b,c;
    REP(i,1,m)  in(a),in(b),in(c),adl(a,b,c);
    Dijkstra();
    REP(i,1,n)  printf("%lld ",dis[i]);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值