蓝桥杯真题:路径

思路:用迪杰斯特拉算法跑一遍,这题的意义在于重温图论里边的一些算法和最小公约数(gcd)最大公倍数的求法(lcm)

这里图采用链式前向星存储边,可以参考这篇博客:

链式前向星(详解)_菜鸡的博客-CSDN博客_链式前向星

而关于迪杰斯特拉算法,可以参考一下这篇博客:

迪杰斯特拉(Dijkstra)算法最通俗易懂的讲解_goodxin_ie的博客-CSDN博客_迪杰斯特拉算法

我的理解就是维护一个距离数组和一个集合s,每次从在s外的点中选出从到s最短的一个点,加入集合,然后更新其他未在集合中的邻接点的最小路径值

代码如下所示:

#include <iostream>
#include <queue>
#include <memory.h>
using namespace std;
typedef long long ll;

const int Max = 1e6 + 5;
int u[Max], v[Max], w[Max];
int g = 0, first[Max], nex[Max];
struct node
{
    int n, w;
    bool operator<(const node& a)const
    {
        return w > a.w;
    }
    node(int a, int b)
    {
        n = a;
        w = b;
    }
};
ll dis[Max], b[Max];
priority_queue<node> que;
//链式前向星存储
void add(int a, int b, int c)
{
    u[++g] = a;
    v[g] = b;
    w[g] = c;
    nex[g] = first[a];//记录上一条以a为起点的边在uvw中的存储位置
    first[a] = g;//以a为起点的最后输入的边的存储位置
}

ll gcd(ll a, ll b)
{
    if (a == 0) return b;
    return gcd(b % a, a);
}

ll lcm(ll a, ll b)
{
    return a * b / gcd(a, b);
}

int main()
{
    // 请在此输入您的代码
    memset(first, -1, sizeof(first));
    memset(dis, 0x7f, sizeof(dis));
    for (int i = 1; i <= 2021; ++i)
    {
        for (int j = i + 1; j - i <= 21 && j <= 2021; ++j)
        {
            add(i, j, lcm(i, j));
            add(j, i, lcm(i, j));
        }
    }
    que.push(node(1, 0));
    dis[1] = 0;
    while (!que.empty())
    {
        node no = que.top();
        que.pop();
        if (b[no.n]) continue;//已经加入集合
        dis[no.n] = no.w;
        b[no.n] = 1;//加入集合
        //对这个节点的所有不在集合中的邻接点 更新最小值
        for (int i = first[no.n]; i != -1; i = nex[i])
        {
            if (b[v[i]]) continue;
            if (dis[u[i]] + w[i] < dis[v[i]])
            {
                dis[v[i]] = dis[u[i]] + w[i];
                que.push(node(v[i], dis[u[i]] + w[i]));
            }
        }
    }
    cout << dis[2021];
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值