寒假训练营 第十一节 搜索与图论(二)总结

图(Graph)是由顶点的有穷非空集台和顶点之间边的集台组成的,通常表示为G(V,E) ,其中, G表示—个图,V是图G中顶点的集台,E是图G中边的集台。

注意:

  • 线性表中我们把数据元素叫元素,树中将数据元素叫结点,在图中数据元素,我们则称之为顶点(Vertex)。
  • 线性表中,相邻的数据元素之间具有线性关系,树结构中,相邻两层的结点具有层次关系,而图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。
  • 在线性表中,元素个数可以为零,称为空表;
    在树中,结点个数可以为零,称为空树;
    中,顶点个数不能为零,但可以没有边。

图的相关术语

无向边:若顶点 v i v_{i} vi v j v_{j} vj之间的边没有方向.用无序
偶对( v i v_{i} vi, v j v_{j} vj)来表示。
有向边:若顶点 v i v_{i} vi v j v_{j} vj之间的边有方向。用有序偶 < v i v_{i} vi, v j v_{j} vj> 来表示。
在这里插入图片描述

无向图:在一个图中,每条边都没有方向。
有向图:在一个图中,每条边都有方向。
无向完全图:在无向图中,任意两个顶点之间都存在边。含有n个顶点的无向完全图有 n x (n-1)/ 2条边。
有向完全图:在一个有向图中,任意两个顶点之间都存在方向相反的两条弧.。含有n个顶点的有向完全图有n×(n-1)条弧.。
注意无向边用小括号“()”表示,而有向边则是用尖括号“<>”表示。
顶点的度:在无向图中,顶点v的度是指依附于该顶点的边数,通常记为TD(v)。
入度:在有向图中,顶点v的入度是指以该顶点为弧头的弧的数目,记为ID(v)。
出度:在有向图中,顶点v的出度是指以该顶点为弧尾的弧的数目,记为OD(v)。
权:有些图的边或弧具有与它相关的数字,这种与图的边或弧相关的数叫做权。(即指对边赋予的有意义的数值量。)
网:边上带权的图,也称网图
路径:在无向图G=(V,E)中,从顶点 v p v_{p} vp到顶点 v q v_{q} vq之间的路径是一个顶点序列( v p v_{p} vp=KaTeX parse error: Expected 'EOF', got '}' at position 6: v_i0p}̲ , v i 1 v_{i1} vi1, v i 2 v_{i2} vi2,…, v i m v_{im} vim= v q v_{q} vq其中,( v i j − 1 v_{ij-1} vij1, v i j v_{ij} vij)∈E( 1≤ j ≤ m )若G是有向图,则路径也是有方向的,顶点序列满足< v i j − 1 v_{ij-1} vij1, v i j v_{ij} vij>∈E。
路径长度:非带权图——路径上边的个数。
带权图——路径上各边的权之和。
回路(环):第一个顶点和最后一个顶点相同的路径。
简单路径:序列中顶点不重复出现的路径。
简单回路(简单环):除了第一个顶点和最后一个顶点外,其余顶点不重复出现的回路。
连通图:在无向图中,如果从一个顶点 v i v_{i} vi到另一个顶点 v j v_{j} vj(i≠j)有路径,则称顶点 v i v_{i} vi v j v_{j} vj是连通的。如果图中 任意两个顶点都是连通的,则称该图是连通图。
连通分量:非连通图的极大连通子图称为连通分量。
在这里插入图片描述

生成树:n个顶点的连通图G的生成树是包含G中全部顶点的一个极小连通子图。
在这里插入图片描述

图的基本操作

  1. CreateGraph(G):输入图G的顶点和边,建立图G的存储。
  2. DFS(G,v):在图G中,从顶点v出发深度优先遍历图G。
  3. BFS(G,v):在图G中,从顶点v出发广度优先遍历图G。

图的存储结构

图的邻接矩阵

图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。
设图G有n个顶点,则邻接矩阵是一个n×n的方阵,定义为:
arc[i][j] = 1 ,若( v i v_{i} vi, v j v_{j} vj)∈E或< v i v_{i} vi, v j v_{j} vj>∈E
arc[i][j] = 0 ,其他
无向图的邻接矩阵是对称的,
有向图的邻接矩阵则不对称。

可以使用邻接矩阵存储一张图:记 v[i][j] 表示从 i 到 j 的边权。如果不通可以设置为 0 或者 inf一个很大的数字)。

/*
对于一个 n 个点 m 条边的图,在使用邻接矩阵时,需要开一个n×n  的数组,即空间复杂度 O(n^2),代码如下:
*/
cin >> n;

for (int i = 1; i <= n; i++)

for (int j = 1; j <= n; j++)
cin >> v[i][j]; // 存入每一对点之间的边权

for (int i = 1; i <= n; i++)

for (int j = 1; j <= n; j++)

if (v[i][j] > 0)
cout << "edge from point " << i << " to point " << j
<< " with length " << v[i][j] << '\n';

可采用 vector 代替二维数组,使用 vector 存储第二维,从而减少空间占用。这种做法被称为邻接表。为了同时存储边的终点与边权,可以采用结构体。

#include <iostream>
#include <vector>
#define MAXN 1005
using namespace std;

struct edge {

// 记录边的终点,边权的结构体
	int to, cost;
};

int n, m; // 图有 n 个点 m 条边
vector <edge> p[MAXN]; // 邻接表
int v[MAXN][MAXN]; // 邻接矩阵
int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int u, v, l;
		cin >> u >> v >> l;
		p[u].push_back((edge) {v, l});
		// p[v].push_back((edge){u, l});
		// 无向图邻接表要加一条反方向的边
	}
}
// 遍历邻接表,把邻接表转换为邻接矩阵
for (int i = 1; i <= n; i++)
	for (int j = 0; j < p[i].size(); j++)
		v[i][p[i][j].to] = p[i][j].cost;

邻接表的优缺点:

  • 优点:总的空间复杂度是O(m) 的,且遍历某个点相邻的节点的时间复杂度为 O§ ,其中 p 为该点的出度。
  • 缺点:如果需要指定查询或修改边<i,j>的边权,需要的时间复杂度为 O§,不如邻接矩阵的 O(1)。
  • 邻接矩阵:适用于点较少(几百)、边较多(稠密图)的情况;
    邻接表:适用于点较多、或者可能出现重边的情况。
题目详情: 洛谷P5318深基18.例3】查找文献

小K 喜欢翻看洛谷博客获取知识。每篇文章可能会有若干个(也有可能没有)参考文献的链接指向别的博客文章。小K 求知欲旺盛,如果他看了某篇文章,那么他一定会去看这篇文章的参考文献(如果他之前已经看过这篇参考文献的话就不用再看它了)。

假设洛谷博客里面一共有 n ( n ≤ 1 0 5 ) n(n\le10^5) n(n105) 篇文章(编号为 1 到 n n n)以及 m ( m ≤ 1 0 6 ) m(m\le10^6) m(m106) 条参考文献引用关系。目前小 K 已经打开了编号为 1 的一篇文章,请帮助小 K 设计一种方法,使小 K 可以不重复、不遗漏的看完所有他能看到的文章。

这边是已经整理好的参考文献关系图,其中,文献 X → Y 表示文章 X 有参考文献 Y。不保证编号为 1 的文章没有被其他文章引用。

请对这个图分别进行 DFS 和 BFS,并输出遍历结果。如果有很多篇文章可以参阅,请先看编号较小的那篇(因此你可能需要先排序)。

法一:DFS

void solve(int x) {
	for (int i = 0; i < p[x].size(); i++)
		if (!u[p[x][i]]) {
			u[p[x][i]] = true;
			solve(p[x][i]);
	}
}

在这里插入图片描述

法二:BFS

while (!q.empty()) {
	int x = q.front();
	q.pop();
	cout << x << ' ';
	for (int i = 0; i < p[x].size(); i++)
		if (!u[p[x][i]]) {
			u[p[x][i]] = true;
			q.push(p[x][i]);
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值