/**
* 图的应用 --- 最短路径 --- 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;
}
}
}
}
}
图的应用 --- 最短路径 --- BFS、Dijkstra、Floyd
于 2022-09-17 17:26:05 首次发布