首页 > 其他分享 >王道408---DS---图

王道408---DS---图

时间:2023-10-12 17:37:23浏览次数:30  
标签:dist int 复杂度 路径 节点 --- 顶点 DS 408

图有关的概念

1、连通图、连通分量是相对于无向图说的,而强连通图、强连通分量是相对于有向图说的

2、生成树,连通图的生成树是包含图中全部顶点的一个极小连通子图。若砍去一条边,则一定变得非连通

3、极大连通子图与极小连通子图,极小连通子图就是生成树,极大连通子图就是无向图的连通分量

极大要求包含该连通子图的所有边,极小要求保持连通且边最小

连通图的连通分量/极大连通子图就是它自己

4、简单路径、简单回路:

在路径序列中,顶点不重复出现的路径称为简单路径。

除第一个顶点和最后一个顶点外,其余顶点不重复出现的回路称为简单回路。

图的存储

一般有四种方法---邻接矩阵法、邻接表法、十字链表法、邻接多重表,常用的只有前两种

邻接矩阵法

#define N 8  		//顶点数目的最大值,根据题目要求自己定义
typedef struct{
	char vex[N];	//N个顶点信息,每个顶点存储一个char字符,可根据题目要求将char改为其他类型
    int weight[N][N];	//N*N邻接矩阵,每条边的权值用int变量表示
	int vexnum,arcnum; 	//图的当前顶点数和弧数
}MGraph;

image-20231006171837465

需要注意的是

1、无向图的邻接矩阵是对称矩阵,对规模特大的邻接矩阵可采用压缩存储。

2、稠密图适合使用邻接矩阵的存储表示。

3、

image-20231006172026268

image-20231008073024652

邻接表法

#define N 8		//图中顶点数目的最大值,根据题目要求自己定义
typedef struct ArcNode{			//弧结点
	int vexIndex;				//该弧所指向的顶点编号
    int weight;                //该弧的权值
	struct ArcNode *next;		//指向下一个弧结点
}ArcNode; 

typedef struct VNode{	//顶点结点
	char data; 			//顶点信息,每个顶点存储一个char字符,可根据题目要求将char改为其他类型
	ArcNode *first; 	//指向第一条依附该顶点的弧的指针
}VNode;

typedef struct{
	VNode vex[N];    		//N个顶点
	int vexnum,arcnum; 		//图的顶点数和弧数
} ALGraph; 	

image-20231006172053044

对于稀疏图,采用邻接表存储比较好

求度的时候需要遍历整个邻接表,为此引出了十字链表法:

十字链表法

十字链表法用于有向图

之前写过一篇:

https://www.cnblogs.com/lordtianqiyi/p/17739953.html

邻接多重表

image-20231008075140061

邻接多重表的画法

比我想象中的简单

https://www.bilibili.com/video/BV1Ae41137Jd/?spm_id_from=333.337.search-card.all.click&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

https://www.bilibili.com/video/BV1TL411b7V3/?spm_id_from=333.337.search-card.all.click&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

1、写出所有的边的关系

image-20231008075758623

2、先画出顶点以及边

image-20231008075954648

3、链接

image-20231008080016690

边的第二个数据项ilink代表指向下一条依附于顶点ivex的边

第四个数据项jlink指向下一个依附于顶点jvex的边

图的遍历

BFS

类似于二叉树的层序遍历

Dijkstra、prim算法就使用到了广度优先的思想

空间复杂度: O(V)

时间复杂度: O(V+E) // 邻接表法 或 O(V^2) // 邻接矩阵法

BFS---广度优先生成树

image-20231006173530708

DFS

类型于二叉树的先序遍历

需要一个递归的栈,空间复杂度为O(V)

邻阶矩阵的时间复杂度是O(V^2)

邻阶表的时间复杂度是O(V+E)

深度优先遍历还可以判断是否存在回路

DFS---深度优先生成树

image-20231006173940146

Prim算法

MST,最小生成树

image-20231006174059607

类似于Dijkstra算法

适合求稠密图的MST

时间复杂度: O(V^2)

Kruskal算法

image-20231006174400806

时间复杂度:O(ElogE)

适合求边稀疏顶点多的图的MST

Dijkstra算法求单源最短路径

image-20231006175704132

image-20231006175715011

image-20231006175722297

不适用于负权值

时间复杂度为O(V^2)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=520;
int n,m;
int g[N][N];    // 存储点到点的距离,即边 ,或者说邻接矩阵 
int dist[N];    // 存储点到原点的距离
bool st[N];        // 标记是否确定了最短路径 

int dijkstra(){
    memset(dist,0x3f,sizeof dist);                            // 为最后的 if(dist[n]==0x3f3f3f3f) return -1;   做铺垫 
    dist[1]=0;                                                // 注意,这里 dist 是从1开始计数的 !!!
    for(int i=0;i<n;i++){    
        int t=-1;
        for(int j=1;j<=n;j++)
            if(!st[j] && (t==-1 || dist[t]>dist[j]))        // 找到距离原点最短距离的点   ,并附加标记   // 有点贪心的思想 
                t=j;
            
        st[t]=true;                        // 附加标记,即最短路径点,收录到最短路径中
        for(int j=1;j<=n;j++) 
            dist[j] = min(dist[j],dist[t]+g[t][j]);            //依次更新每个点所到相邻的点路径值 // dist[t] <=> 0->t | g[t][j] <=> t->j |  ===>  dist[t]+g[t][j] <=> 0->j
    }
    
    if(dist[n]==0x3f3f3f3f) return -1;  
    return dist[n]; 
}

int main(){
    cin >> n >> m;
    memset(g,0x3f,sizeof g);                                // 为 g[a][b] = min(g[a][b],x); 做铺垫 
    while(m--){
        int a,b,x;
        scanf("%d%d%d",&a,&b,&x);
        g[a][b] = min(g[a][b],x);
    }
    
    int t=dijkstra();
    printf("%d\n",t);
    
    return 0;
}

Dijkstra 算法思路

1、每次从未标记的节点中选择距离出发点最近的节点,标记,收录到最优路径集合中。

2、计算刚加入节点A的邻近节点B的距离(不包含标记的节点)

若(节点A的距离+节点A到节点B的边长)<节点B的距离,就更新节点B的距离和前面点。

3、反复循环

Floyd算法求多源最短路径

时间复杂度为O(V^3)

image-20231010081244030

算法思想:

image-20231012161131827

  1. floyd 算法遍历每个点,每个点都会找到从该点到其他所有点的最短路径,我们从一个点来入手研究,比如我们选取点 0
  2. 选取点 0后,遍历除0外的所有点,每遍历一个点就把该点作为中轴节点x,并比较 所有的A[i][x] + A[x][0] 与 A[i][0]的大小,若前者小,则更新A_i中最短路径的大小,且更新 Path_i中的 记录的中轴节点

Path_i 表的作用: 这个表记录所有最短路径的中轴节点如" Path[0][2] = 3" 代表的含义是: A[0][2] > A[0][3] + A[3][2] ,也就是说以3为转轴的时候 节点0到2 的直接距离小于先从 0到3,再从3到2的距离和

当然,上图中是已经比较后且修改过的图,下图是比较前的图:

image-20231012162049390

/*
 * floyd最短路径。
 * 即,统计图中各个顶点间的最短路径。
 *
 * 参数说明:
 *        G -- 图
 *     path -- 路径。path[i][j]=k表示,"顶点i"到"顶点j"的最短路径会经过顶点k。
 *     dist -- 长度数组。即,dist[i][j]=sum表示,"顶点i"到"顶点j"的最短路径的长度是sum。
 */
void floyd(Graph G, int path[][MAX], int dist[][MAX])
{
    int i,j,k;
    int tmp;

    // 初始化
    for (i = 0; i < G.vexnum; i++)
    {
        for (j = 0; j < G.vexnum; j++)
        {
            dist[i][j] = G.matrix[i][j];    // "顶点i"到"顶点j"的路径长度为"i到j的权值"。
            path[i][j] = j;                 // "顶点i"到"顶点j"的最短路径是经过顶点j。
        }
    }

    // 计算最短路径
    for (k = 0; k < G.vexnum; k++)
    {
        for (i = 0; i < G.vexnum; i++)
        {
            for (j = 0; j < G.vexnum; j++)
            {
                // 如果经过下标为k顶点路径比原两点间路径更短,则更新dist[i][j]和path[i][j]
                tmp = (dist[i][k]==INF || dist[k][j]==INF) ? INF : (dist[i][k] + dist[k][j]);
                if (dist[i][j] > tmp)
                {
                    // "i到j最短路径"对应的值设,为更小的一个(即经过k)
                    dist[i][j] = tmp;
                    // "i到j最短路径"对应的路径,经过k
                    path[i][j] = path[i][k];
                }
            }
        }
    }

    // 打印floyd最短路径的结果
    printf("floyd: \n");
    for (i = 0; i < G.vexnum; i++)
    {
        for (j = 0; j < G.vexnum; j++)
            printf("%2d  ", dist[i][j]);
        printf("\n");
    }
}

这个算法还是比较简单的,需要注意的是,floyd算法每次选取一个中介点,然后进行两重循环

拓扑排序

AOV网: 顶点表示活动的网络

拓扑排序要求:

①每个顶点出现且只出现一次。
②若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径。

拓扑排序可以判断有无环

由于AOV网中各顶点的地位平等,每个顶点编号是人为的,因此可以按拓扑排序的结果重新编号,生成AOV网的新的邻接存储矩阵,这种邻接矩阵可以是三角矩阵:但对于一般的图来说,若其邻接矩阵是三角矩阵,则存在拓扑序列:反之则不一定成立。

邻接表时间复杂度为O(V+E),临界矩阵为:O(V^2)

关键路径

AOE网

求关键路径

https://www.bilibili.com/video/BV1eZ4y1e7Qm/?spm_id_from=333.337.search-card.all.click&vd_source=87f7ad8544d4c3ad070c5c2ff28b7698

image-20231008081633167

1、事件最早发生时间

拓扑排序

image-20231008081651376

2、事件最迟发生时间

逆拓扑排序

image-20231008081701317

3、活动最早开始时间 ei

image-20231008081709837

4、活动最晚开始时间 li

image-20231008081719826

5、求时间余量 li-ei

image-20231008081727740

时间余量为0的点为关键路径

中缀表达式转有向无环图

image-20231010093242937

image-20231010094546779

我的感悟是先按中序建树,然后再去边

经典错题---6.4

若有向图的拓扑有序序列唯一,则图中每个顶,点的入度和出度最多为1

这句话是错误的

image-20231010081904833

在图G的最小生成树G中,某条边的权值可能会超过未选边的权值

这是因为权值小的图不一定连通

image-20231010082141196

总结

1、在路径序列中,顶点不重复出现的路径称为简单路径。

2、dfs算法与bfs算法发时间复杂度与空间复杂度分析

空间复杂度: O(V)

时间复杂度: O(V+E) // 邻接表法 或 O(V^2) // 邻接矩阵法

3、prim,kruskal,Dijkstra,floyd算法的时间复杂度

prim: O(v^2)

kruskal : O(eloge)

Dijkstra : O(v^2)

floyd : O(v^3)

4、Dijkstra 算法思路(真题常考,并且算法比prim与kruskal复杂一点,故专门记录)

  1. 每次从未标记的节点中选择距离出发点最近>的节点,标记,收录到最优路径集合中。

  2. 计算刚加入节点A的邻近节点B的距离(不包含标记的节点)

    若(节点A的距离+节点A到节点B的边长)<节点B的距离,就更新节点B的距离和前面点。

  3. 反复循环

题目中会问,当找到第n个最短路径时,dist数组的内容是多少,需要注意的是,当找到第n个最短路口路径后,需要更新一次dist,再回答题目

标签:dist,int,复杂度,路径,节点,---,顶点,DS,408
From: https://www.cnblogs.com/lordtianqiyi/p/17760062.html

相关文章

  • 王道408---DS---查找
    基本概念ASL平均查找长度在查找过程中,一次查找的长度是指需要比较的关键字次数,而平均查找长度则是所有查找过程中进行关键字的比较次数的平均值顺序查找与折半查找一般线性表的顺序查找没啥好说的有序表的顺序查找树中的圆形结点表示有序线性表中存在的元素;树中的矩形结点......
  • 王道408---DS---线性表、栈、队列与数组
    错题2.21、题目中提到在第i个位置一般是指在下表为i的位置2、线性表元素的序号是从1开始,而在第n+1个位置插入相当于在表尾追加。静态链表树的双亲表示法就是使用了这种思想吧卡特兰数\[\text{}\frac1{n+1}C_{2n}^{n}\]栈的数学性质:n个不同元素进栈,出栈元素不同排列的个......
  • 王道408---DS---树、二叉树、图
    有序树、无序树的概念有序树和无序树,树中结点的各子树从左到右是有次序的,不能互换,称该树为有序树,否则称为无序树。树/二叉树的性质树的性质常用的只有第一个二叉树的性质常用公式也只有这一个二叉树的存储一般分为顺序存储与链式存储要求顺序存储能默写顺序存储:typ......
  • IMX6ULL裸机-RTC定时器
    1引入RTC定时器RTC定时器被叫做实时时钟(realtimeclock)。CPU内部有很多定时器,像看门狗WDT,PWM定时器,高精度定时器Timer等等,只在“启动”即“通电时”运行,断电时停止。当然,如果时钟不能连续跟踪时间,则必须手动设置。那么当关机后就没办法自动计数统计时间了。定时器的本质就......
  • Fi-GNN: Modeling Feature Interactions via Graph Neural Networks for CTR Predicti
    目录概Fi-GNN代码LiZ.,CuiZ.,WuS.,ZhangX.andWangL.Fi-GNN:Modelingfeatureinteractionsviagraphneuralnetworksforctrprediction.CIKM,2019.概"图网络"用在精排阶段(算哪门子图网络啊).Fi-GNN一个item可能有多种field,比如:\[\underbrace......
  • python+playwright 学习-61 Playwright 和 Selenium 的区别是什么?
    前言最近有不少同学问到Playwright和Selenium的区别是什么?有同学可能之前学过selenium了,再学一个playwright感觉有些多余,可能之前有项目已经是selenium写的了,换成playwright需要时间成本,并且可能有未知风险。也有同学之前可能没学过selenium,现在正准备入手一个web......
  • 2020-2021 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror
    有五种种类的垃圾,数量分别为\(a_1,a_2,a_3,a_4,a_5\)。第一种为纸质垃圾第二种为塑料垃圾第三种双非垃圾第四种基本纸质垃圾第五种基本塑料垃圾有三种垃圾桶,容量分别为\(c_1,c_2,c_3\)。第一种垃圾桶可以放入:纸质垃圾和基本纸质垃圾第二种垃圾桶可以放入:塑料......
  • Python - 深拷贝一个带有指向自身引用的列表,会报错么?紧接着用==比较,会报错么?
    问题描述深拷贝一个带有指向自身引用的列表:列表x中有指向自身的引用,因此x是一个无限嵌套的列表。importcopyx=[1]x.append(x)>>x[1,[...]]y=copy.deepcopy(x)>>y[1,[...]] 深拷贝不报错但是我们发现深度拷贝x到y后,程序并没有出现stackoverf......
  • Java设计模式-单例模式
    1、用到过的场景需要一样的对象放入数组中构建类的方式固定2、饿汉模式(不要用)packagecom.cc.eed.sin;/***<p>单例模式-饿汉(线程不安全)</p>**@authorCC*@since2023/10/12*/publicclassSingletonDemo2{privatestaticfinalSingletonDemo2......
  • import, export,export default,exports - 导入导出方法总结
    1.Export注意:在一个模块中,export可以向外暴露多个注意;使用export导出的成员,必须严格按照导出时候的名称,不能自定义,来使用{}按需接收注意;使用export导出的成员,如果要换个名称,可以使用as起别名模块是独立的文件,该文件内部的所有的变量外部都无法获取。如果希望获取某个变......