算法笔记--数据结构--图-最短路径

Dijkstra算法

迪杰斯特拉算法用来解决单源最短路问题,即给的图G和起点s,通过算法得到s到达其他每个顶点的最短距离

概念

基本思想:对图G(V,E)设置集合S,存放已被访问顶点,然后每次从集合V - S中选择与起点s的最短距离最小的一个顶点(记为u),访问并加入集合S。之后,令顶点u为中介点,优化起点s与所有从u能到达的顶点v之间的最短距离,操作n次(n为顶点数),直到集合S包含所有顶点

例子

Snipaste_2020-04-20_11-44-18

Snipaste_2020-04-20_11-44-25

邻接矩阵

#include<cstdio>

const int MAXV = 1000;
const int INF = 100000000;

int n, G[MAXV][MAXV];
int dist[MAXV];
bool vis[MAXV] = {false};

void Dijkstra(int s){
    fill(dist, dist + MAXV, INF);
    dist[s] = 0;
    for(int i = 0; i < n; i++){
        int u = -1, MIN = INF;
        for(int j = 0; j < n; j++){
            if(vis[j] == false && dist[j] < MIN){
                u = j;
                MIN = dist[u];
            }
        }
        
        if(u == -1) return;
        vis[u] = true;
        for(int v = 0; v < n; v++){
            if(vis[v] == false && G[u][v] != INF && dist[u] + G[u][v] < dist[v]){
                dist[v] = dist[u] + G[u][v];
            }
        }
    }
}

邻接表

#include<cstdio>
#include<vector>
using namespace std;
const int MAXV = 1000;
const int INF = 100000000;

struct node{
    int v, dist; // v为边的目标顶点,dis为边权
};

int n;
vector<node> Adj[MAXV];
int dist[MAXV];
bool vis[MAXV] = {false};

void Dijkstra(int s){
    fill(dist, dist + MAXV, INF);
    dist[s] = 0;
    for(int i = 0; i < n; i++){
        int u = -1, MIN = INF;
        for(int j = 0; j < n; j++){
            if(vis[j] == false && dist[j] < MIN){
                u = j;
                MIN = dist[j];
            }
        }
        if(u == -1) return;
        vis[u] = true;
        for(int j = 0; j < Adj[u].size(); j++){
            int v = Adj[u][j].v;
            if(vis[v] == false && dist[u] + Adj[u][j].dist < dist[v]){
                dist[v] = dist[u] + Adj[u][j].dist;
            }
        }
    }
}

以上所计算的是最短路径,为了计算得到最短路径,设置pre[]数组,令pre[v]表示从起点s到顶点v的最短路径上v的前一个顶点(即前驱结点)的编号

#include<cstdio>

const int MAXV = 1000;
const int INF = 100000000;

int n, G[MAXV][MAXV];
int dist[MAXV];
int pre[MAXV];
bool vis[MAXV] = {false};

void Dijkstra(int s){
    fill(dist, dist + MAXV, INF);
    dist[s] = 0;
    for(int i = 0; i < n; i++){
        int u = -1, MIN = INF;
        for(int j = 0; j < n; j++){
            if(vis[j] == false && dist[j] < MIN){
                u = j;
                MIN = dist[u];
            }
        }
        
        if(u == -1) return;
        vis[u] = true;
        for(int v = 0; v < n; v++){
            if(vis[v] == false && G[u][v] != INF && dist[u] + G[u][v] < dist[v]){
                dist[v] = dist[u] + G[u][v];
                pre[v] = u;			// 记录v的前驱顶点是u(新添加)
            }
        }
    }
}

之后,利用递归来求出整条路径:

void DFS(int s, int v){		// s为起点编号,v为当前访问的顶点编号
    if(s == v){
        printf("%d
", s);
        return;
    }
    DFS(s, pre[v]);
    printf("%d
", v);
}

Snipaste_2020-04-20_14-36-18

三种常见题型

Snipaste_2020-04-20_14-37-39

Snipaste_2020-04-20_14-37-47

Snipaste_2020-04-20_14-38-46

Snipaste_2020-04-20_14-38-54

Write by Gqq

原文地址:https://www.cnblogs.com/zgqcn/p/12783440.html