今天开始学习图论相关的算法。
今天学习内容:
图论相关概念,图的两个存储结构,图的bfs,dfs遍历,拓扑序。
- 1,图论相关概念
# 图
vertex:点
edge:边 或顶点偶对称
有向图: <x, y> 由x--> y;
无向图: (x,y) NOTICE:特殊的有向图
## 图的基本术语
完全图:n(n-1)/2 -- 无向图 不除二 -- 有向图
权和网:
权:每条边上可以标上具有某种含义的数值,该数值为权。可以表示距离或耗费。
网:带权的图
邻接点:两点可相连
度:
顶点v的度是指和v相关联的边的数目。记为:TO(v);
入度:以顶点v为头的弧的数目。记为:ID(v);
出度:以顶点v为尾的弧的数目。记为:OD(v)
**TO(v) = ID(v) + OD(v)**
路径和路径长度:
回路或环
连通,连通图和连通分量:
再G中,如果v->v'有路径,表示v和v'是连通的
全部都是连通的,是连通图
连通分量 是连通子图。
## 图的存储结构
### 邻接矩阵:
就是二维数组,g[a,b] a-->b O(n*2)
### 邻接表
图的链式存储结构。在邻接表中,对图中每一个顶点vi建立一个单链表
## 拓扑序列:有向图 都是从前指向后的
有向无环图,被称为拓扑图
有向无环图一定至少存在一个入度为0的点
## 最短路
### 单源最短路
#### 所有边权都是正数
1, 朴素Dijkstra算法
2, 堆优化版的Dijkstra算法
#### 存在负权边
1, Bellman-Ford
2, SPFA
### 多源汇最短路
Floyd算法
源点 起点 汇点 终点
- 2,图的两个存储结构
第一种:邻接矩阵。二维数组ph[][] -- 适用于稠密表
第二种:邻接表。用数组模拟链表。 -- 适用于稀疏表。
重点讲一下邻接表:
全局变量: h[] e[] ne[] idx;
//初始化:
void init() {
memset(h,-1,sizeof(h) ); // <cstring>
}
// 增添;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
注意头结点的初始化,这个容易忘掉。
- 3,遍历
遍历主要分为bfs和dfs两个遍历。
BFS:
void bfs() {
int hh = 0, tt = 0; // q[] 数组模拟队列
// 入列
while(hh <= tt) { // hh <= tt -- > 队列不为空
int t = q[hh++]; // 出队
for(int i = h[t]; i != -1; i = ne[i]) { // 邻接表
int j = e[i];
if(d[j] == -1) {
// 执行
q[++t] = j; // 入队
}
}
}
// 产生结果
}
DFS:
void dfs(int u) {
int sum = 1, res = 0;
for(int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if(!st[j]) {
// 过程
dfs(j);
}
}
// 结果
}
- 4,拓扑排序
有向无环图(DAG。顶点的线性排序
所需算法:邻接表,队列
算法步骤:
- 遍历。将入度为0的点入队。
- 出列,弹出。邻接点入度减一,若邻接点入度为0就入队。
- 判断入队个数与顶点个数,相等表示是有向无环图,可以进行拓扑排序,反之有环不可以。
d[] 表示点的入度。
bool toposort() {
int hh = 0, tt = -1; // 模拟队列
for(int i = 1; i <= n; ++i) {
if(d[i]) q[++tt] = i; // 入度0的入队
}
while(hh <= tt) {
int t = q[hh++];
for(int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
d[j]--;
if(d[j] == 0) q[++tt] = j;
}
}
return tt == n-1; // true -- 有向无环图
}
- 5,做题巩固。
在洛谷上做了P3916 图的遍历和P2712 摄像头,都是拓扑模板题。
P3916 图的遍历 解题思路:反建图,dfs,画个图看看就出来了。
P2712 摄像头 解题思路:去掉没有摄像头的区间,其他的拓扑排序,按上面模板来。
做题总结:算法思路很好理解,就是写的时候像点,邻接点,入度等会搞混,头结点没有赋初值 ( memset(h,-1,sizeof(h) ) )。学到了许多。像第二题,用vector<int>存可能size为0,这个时候size() == 0 但是由于size范围不是int型,会导致size()-1是很大的值,所以以后用size()时候要先用int存一下,进行类型转换,防止过大。
今日总结:图的知识有点绕,算法和算法模板好理解,就是总是丢三落四,让算法题AC不了。