- 本节课程非常的重要,是图论的基础与入门部分。这节课将会影响下一节图论课的效果,所以请务必认真听讲
- 听讲 + 大量的巩固练习非常重要
图的初步(主要内容) 数论初步(可以归为数据结构一块)
- 图的概念 · 树是什么
- 图的存储 · 树(二叉树)的简单性质
- 图的遍历 · 树(二叉树)的存储
- 简单图论问题与图论应用 · 树(二叉树)的遍历
- · 简单树论问题与应用
一、图论简介——图是什么
- 图:表示物与物之间关系的方法
- 图论:以图为研究对象,研究顶点和边组成的图形的数学理论和方法
- 一般是 n 个点,m 条边
- 边的方向:
- 无向图:边双向连通(一种特殊的有向图,双向)
- 有向图:单向通行
- 边权
- 度:与此点相连边的数量
- 入度:流入此点的边的数量
- 出度:流出此点的边的数量
- 出、入度一般都用于有向图
二、图的存储
图的存储——邻接矩阵
- 邻接矩阵:用二维数组的方式存储一个图
- 存储规则:若 a—>b,则 map[ a ][ b ] = ( a 到 b 的距离 或1 ),无法访问值为 -1 或 正无穷
- a—>a = 0
- 无向图:map[ a ][ b ] = map[ b ][ a ]
- 空间复杂度 O(n2) 遍历一个点的时间复杂度 O(n)
- 由于邻接矩阵时空复杂度较大,在多数情况下效率较低,尤其是当图比较稀疏(边数远没有达到点数平方)时。(例如有 1000 个点,但仅有 1000 条边时,为边开的空间大小是 1000*1000,就会很浪费)所以基本不用邻接矩阵。
1 #inclu e <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=1005; // 图的最大 点 数量 5 int n; 6 int v[maxn][maxn]; 7 8 int main() 9 { 10 cin>>n; 11 12 // 读入邻接矩阵 13 for(int i=1; i<=n; i_++) 14 for(int j=1; j<=n; j++) 15 cin>>v[i][j]; 16 17 // 下面的代码将找到与点 i 有直接连接的每一个点以及那条边的长度 18 for(int i=1; i<=n; i++) 19 for(int j=1; j<=n; j++) 20 if(v[i][j]>0) 21 printf("edge from point %d to point %d with length %d\n", i, j, v[i][j]); 22 23 return 0; 24 }
图的存储——邻接表
- 相对于邻接矩阵,进行了优化(只需哪两个点相连,便存这条边)
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 // edge 结构体 { to:边的终点;cost:边权} 5 struct edge 6 { 7 int to, cost; 8 }; 9 10 const int maxn=1005; 11 int n, m; // 表示图中有 n 个点,m 条边 12 vector<edge> p[maxn]; // 建表,开动态数组 vector <edge> p[maxn]; 13 int w[maxn][maxn]; 14 15 int main() 16 { 17 cin>>n>>m; 18 19 // 读入边 < u, v, l >:p[u].push_back((edge){v, l}) 20 for(int i=1; i<=m; i++){ 21 int u, v, l; 22 cin>>u>>v>>l; 23 p[u].push_back((edge){v, l}); 24 p[v].push_back((edge){u, l}); // 当用无向图的邻接表时需要加一条反方向的边 25 } 26 27 // 把邻接表转换为邻接矩阵 28 for(int i=1; i<=n; i++) 29 for(int j=1; j<=p[i].size(); j++) 30 w[i][p[i][j].to] = p[i][j].cost; 31 32 // 输出邻接矩阵 33 for(int i=1; i<=n; i++){ 34 for(int j=1; j<=n; j++) 35 cout<<w[i][j]<<' '; 36 cout<<endl; 37 } 38 39 // u 的出度:p[u].size() 40 41 return 0; 42 }