图的应用 --- 最短路径 --- BFS、Dijkstra、Floyd

/**
 * 图的应用 --- 最短路径 --- BFS、Dijkstra、Floyd
 *
 * ①算法思想
 * 1.BFS求解单源最短路径(适用于不带权或者权值相等的)
 * 
 * 2、Dijkstra求解单源最短路径的思想和prim很像,
 * Dijkstra也是贪心算法,刚开始先把能访问到的点初始化一下,然后在dis里面找一个最小的(prim那边是length),然后把这个点访问掉,
 * 然后通过这个点再继续访问其他的点,进行更新。
 * Dijkstra和Prim不同的地方就在于更新:
 * Prim是最小生成树,每打通一个点圈进来之后,寻找这个访问圈内所有的点与周围未被访问的点的距离最小的点
 * (通过新加入的点与它相连接的顶点的距离和原本的length[]数组的距离进行比较更新实现的),
 * 而Dijkstra是最短路径,每打通一个点之后,就可以通过这个点到达其他的点,
 * 比较从源点经过这个打通的点到它所连通的点的距离 和 原来通过一些其他点到这些连通的点或者源点到这些连通的点的dis(总之就是原来的dis),
 * 如果小于原来的dis,就更新,
 * 然后比较这一轮的dis拿到最小的那个dis的顶点,标记为访问、打通它,然后重复同样的步骤......
 * (举个简单的例子:假设中国每个省会与其他所有省会之间都有直达铁路,prim是研究怎么用最少的里程连接所有省会,
 * dijkstra是研究从某一个省会(比如昆明)出发到其他各省会的最短路径;
 * 可以想象昆明到哈尔滨在prim里是不会直连的因为这个边的权值太大,而在dijkstra里一定是直连的。)
 * 时间复杂度:O(|v|^2)
 * 
 * 3、Floyd求解每对顶点最短路径。
 * 时间复杂度:O(|v|^3)
 * 
 * 
 * ②算法设计
 *
 */

#include <stdio.h>
#include <iostream>
#include <cstdio>
#include <malloc.h>
#include <cstdlib>
#define MaxSize 20
#define INF 999999

struct ArcNode{
    int adjvex;
    struct ArcNode *next;
    int weight;
};
struct VNode{
    char value;
    struct ArcNode *first;
};
struct AdGraph{
    VNode vertices[MaxSize];
    int vexnum,arcnum;
};

//1、BFS求解单源最短路径
void BFSMinPath(AdGraph G,int v,int *visited,int *dis,int *path){//dis[]是用来表示某个顶点到起点距离的数组
    //先初始化
    for (int i = 0; i < G.vexnum; ++i) {
        dis[i] = INF;
        path[i] = -1;
        visited[i] = 0;
    }
    //先把源点访问掉
    dis[v] = 0;
    visited[v] = 1;
    //源点下标BFS入队
    int Queue[MaxSize],front = -1,rear = -1;
    Queue[++rear] = v;
    while(rear != front){
        v = Queue[++front];
        ArcNode *p = G.vertices[v].first;
        //探索一下
        while(p){
            //没必要比较,原因看图
//            if(visited[p -> adjvex] == 0 && dis[p -> adjvex] > dis[v] + 1){
//                dis[p -> adjvex] = dis[v] + 1;
//                path[p -> adjvex] = v;//p -> adjvex 这个下标的顶底是从顶点v过来的
//            }
            if(visited[p -> adjvex] == 0){
                dis[p -> adjvex] = dis[v] + 1;
                path[p -> adjvex] = v;
                visited[p -> adjvex] = 1;
                Queue[++rear] = p -> adjvex;
            }
            p = p -> next;
        }
    }
}
//2、Dijkstra求解单源最短路径
void Dijkstra(AdGraph G,int v,int *dis,int *path,int *visited){
    for (int i = 0; i < G.vexnum; ++i) {
        dis[i] = INF;
        path[i] = -1;
        visited[i] = 0;
    }
    //源点加进来
    dis[v] = 0;
    visited[v] = 1;
    ArcNode *p = G.vertices[v].first;
    while(p){
        dis[p -> adjvex] = p -> weight;
        path[p -> adjvex] = v;
        p = p -> next;
    }
    int min,minIndex;
    for (int i = 0; i < G.vexnum - 1; ++i) {//i是用来计数的,没有实际含义
        min = INF;
        for (int j = 0; j < G.vexnum; ++j) {
            if(visited[j] == 0 && dis[j] < min){
                min = dis[j];
                minIndex = j;
            }
        }
        visited[minIndex] = 1;
        p = G.vertices[minIndex].first;
        while(p){
            //只有这一部分和prim有区别
            if(visited[p -> adjvex] == 0 && dis[p -> adjvex] > dis[minIndex] + p -> weight){
                dis[p -> adjvex] = dis[minIndex] + p -> weight;
                path[p -> adjvex] = minIndex;
            }
            p = p -> next;
        }
    }
}

struct MGraphW{
    char vex[MaxSize];
    int weight[MaxSize][MaxSize];
    int vexnum,arcnum;
};
//3、Floyd求解每对顶点间最短路径(用邻接矩阵)
void Floyd(MGraphW G,int *A[],int *path[]){//注意二维数组这边传入的参数不能写成:int *A,int *path
    //二维数组还可以这样传:int A[][MaxSize],int path[][MaxSize];就是说要把列数限定
    //或者就是前两行使用的方法:在C语言中,二维数组是一行一行的一维数组,把第一个一维数组的地址传进去就是*A[]
    //再或者是二级指针的方式,写成:int **A,int **path
    //初始化
    for (int i = 0; i < G.vexnum; ++i) {
        for (int j = 0; j < G.vexnum; ++j) {
            A[i][j] = G.weight[i][j];
            path[i][j] = -1;
        }
    }
    //讨论中转点问题:对任意两个点i、j,都会试一下k这个中转点
    for (int k = 0; k < G.vexnum; ++k) {
        for (int i = 0; i < G.vexnum; ++i) {
            for (int j = 0; j < G.vexnum; ++j) {
                if(A[i][j] > A[i][k] + A[k][j]){
                    A[i][j] = A[i][k] + A[k][j];
                    path[i][j] = k;
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值