一、图的基本类型
1.无向图:每条边都是无方向的
2.有向图:每条边都是有方向的
3.完全图:任意两个顶点都存在一个边
ㅤㅤㅤㅤ完全无向图ㅤㅤㅤㅤㅤㅤ完全有向图
n个顶点的完全无向图有n(n−1)/2条边
n个顶点的完全有向图有n(n−1)条边(是无向图的两倍)
无向图G中顶点数为n,则图至少有0条边,至多有n(n−1)/2条边。若G为有向图,则至少有0条边,至多有n(n−1)/2条边。
连通图:无向图中任意两个点都有路径可达
ㅤㅤㅤㅤ是连通图ㅤㅤㅤㅤㅤㅤㅤㅤㅤ不是连通图
二、邻接矩阵存储图
无向图:
无向图的左上半部分与右下半部分对称
顶点i的度=第i行(列)中1的个数
有向图:
有向图不一定对称
顶点的出度=第i行元素之和,顶点的入度=第i列元素之和,图的度=1的个数∗2
总结:
无向图可以从v1走到v2,也可以从v2走到v1,所以a[v1][v2]
和a[v2][v1]
都要存
有向图可以从v1走到v2,但不能从v2走到v1,因为有向图是有方向的,所以只用存a[v1][v2]
三、邻接表(链式前向星)存图
无向图:
有向图:
一般来说,邻接表是用数组模拟链表的方式进行存储的,当然也可以用vector
四、图的遍历
一个有n个结点的无向连通图,这些结点以编号:1、2、……n进行编号,现给出结点间的连接关系。请以结点1为起点,优先访问小编号结点的顺序遍历并输出该图。
深度优先搜索(dfs)
我们只需要用邻接矩阵存图,然后从1号结点开始搜索。搜索这个结点的时候,先标记走过,然后输出,再向其他点搜索,如果该点没有访问过,则搜索该点。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,e,a[20][20],x,y;
bool b[20];
void dfs(ll x1) {
b[x1]=true;
printf("%lld ",x1);
//向其他点搜索
for(ll i=1; i<=n; i++) {
//如果没有走过而且可以走
if(a[x1][i]==1&&!b[i]) dfs(i);
}
}
int main() {
scanf("%lld%lld",&n,&e);
for(ll i=1; i<=e; i++) {
scanf("%lld%lld",&x,&y);
a[x][y]=1;
a[y][x]=1;
}
dfs(1);
return 0;
}
广度优先搜索(bfs)
用邻接矩阵存储图,然后用b数组存储该点是否访问过,这里我使用STL中的队列queue来标记。搜索的过程我就不多说了,跟深搜是差不多的。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,e,x,y,a[20][20];
bool b[20];
queue<ll> q;
int main() {
scanf("%lld%lld",&n,&e);
for(ll i=1; i<=e; i++) {
scanf("%lld%lld",&x,&y);
a[x][y]=1;
a[y][x]=1;
}
b[1]=true;
q.push(1);
printf("1 ");
while(!q.empty()) {
//向其他点搜索
for(ll i=1; i<=n; i++) {
//如果没有走过而且可以走
if(!b[i]&&a[q.front()][i]==1) {
q.push(i);
b[i]=true;
printf("%lld ",i);
}
}
q.pop();
}
return 0;
}
佬,“无向图G中顶点数为n,则图至少有0条边,至多有n(n−1)/2条边。若G为有向图,则至少有0条边,至多有n(n−1)/2条边。”这句话应说明一下是简单图吧?不然重边自环就难说了
默认是无重边自环的
题目不严谨可能是会有默认的,但是这是零基础教程欸(我就是提个建议)
有没有一种可能,完全图的字与图放反了🤔
23333333
谢谢大佬提醒