模板 - Dijkstra

模板 - Dijkstra

题目链接 :畅通工程续


​ 这个算法是最短路中可操作性最强的一种了,使用了for循环,可以保证没个点只会经过一次,在这个基础上,我们可以保存最短路径,甚至,还可以保存满足条件的次短路L2-001. 紧急救援 。而且在出现了重边时,这时可以快速的处理。如果用了vector就会很麻烦。


代码

#include <iostream>
#include <cstring>
#include <set>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;i ++)
#define per(i,j,k) for(int i = j;i >= k;i --)

typedef long long ll;
const int MAXN = (int) 2007 ;
const int INF = (int)0x3f3f3f3f;
int G[MAXN][MAXN];
int dis[MAXN];
int vis[MAXN];

void init(){
    memset(dis,0x3f,sizeof(dis));
    memset(G,0x3f,sizeof(G));
    memset(vis,0,sizeof(vis));
}

int main()
{
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);

    int N,M;

    while (cin >> N >> M){
        init();

        int x,y,w;
        rep(i,0,M-1) {
            cin >> x >> y >> w;
            if (w >= G[x][y]) continue;
            G[x][y] = G[y][x] = w;
        }

        int S,E;
        cin >> S >> E;

        dis[S] = 0;

        int now;
        rep(j,0,N-1) {
            int mn = INF;
            int index = -1;
            rep(i,0,N-1){
                if (mn > dis[i] && !vis[i]){
                    mn = dis[i];
                    index = i;
                }
            }
            if (index == -1)break;
            now = index;
            vis[index] = 1;
            rep(i,0,N-1){
                if (dis[i] > G[now][i] + dis[now]){
                    dis[i] = G[now][i] + dis[now];
                }
            }
        }

        if (dis[E] == INF)cout << -1 << endl;
        else            cout << dis[E] << endl;
    }
}
Dijkstra算法是一种用于解决带权图的单源最短路径问题的贪心算法。它维护一个距离起点的最短路径已知的顶点集合,通过不断地扩展这个集合,最终得到从起点到所有顶点的最短路径。 Dijkstra算法的基本思想是,维护一个集合S,表示已经求出最短路径的顶点集合。一开始,S只包含起点。然后,每次从集合V-S中选取一个距离起点最近的顶点u,将其加入集合S中,并更新与u相邻的所有顶点的最短路径。 具体实现上,我们可以使用一个数组dis[]来存储每个顶点到起点的最短路径长度,数组vis[]表示该顶点是否已经被加入到集合S中。每次选取距离起点最近的顶点u后,我们遍历u的所有邻居v,并更新dis[v]的值,如果dis[v]发生了改变,我们就将v加入到一个优先队列中,等待下一次选择。 以下是Dijkstra算法的伪代码实现: ``` int n; // 顶点数 int dis[N]; // 存储起点到每个顶点的最短距离 bool vis[N]; // 标记每个顶点是否已经加入集合S中 vector<pair<int, int>> adj[N]; // 存储每个顶点的邻居 void dijkstra(int s) { // s为起点编号 memset(dis, 0x3f, sizeof dis); // 将dis数组初始化为无穷大 dis[s] = 0; // 起点到自身的距离为0 priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q; q.push({0, s}); // 将起点加入队列中 while (!q.empty()) { auto t = q.top(); q.pop(); int u = t.second; if (vis[u]) continue; // 如果该点已经在集合S中,直接跳过 vis[u] = true; // 将u加入集合S中 for (auto [v, w] : adj[u]) { // 遍历u的所有邻居 if (dis[v] > dis[u] + w) { // 如果从u到v的距离更短 dis[v] = dis[u] + w; // 更新dis数组 q.push({dis[v], v}); // 将v加入队列中 } } } } ``` 其中,priority_queue是一个优先队列,用于存储待选顶点。我们使用了STL中的pair来表示顶点与其到起点的距离。优先队列默认按照pair的第一个元素排序,因此我们需要自定义一个比较函数,将pair按照第二个元素(距离)排序。 Dijkstra算法的时间复杂度为O(ElogV),其中E为边数,V为顶点数。在实际应用中,Dijkstra算法的效率很高,能够处理大规模的图。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值