C++图论(GT)

图论的定义

图是由若干个顶点和一部分边所构成的图形,这种图形通常用来描述某些事物或人之间的某种特定关系。顶点用于代表事物,连接两顶点的边则用于表示两个事物间具有某种关系。
如图所示:

可以看出1和2有某一种关系,1和3也有某一种关系,1和4也是如此。
当然,这一种关系是由自己来定义的,比如关系代表有联系,那么就是1和2有联系,1和3也有联系,1和4也有联系。

有向图和无向图

有向图(Directed graph)就是在一个图里有箭头,如图。
在这里插入图片描述
在上述图片中就和原来的定义不一样了,原来是1和2互相联系,而现在就只能让1联系2,不能让2联系1了。
而无向图(Undirected graph)与最开始的图一样,可以互相联系。

图的遍历

图的遍历有很多种,如邻接表、邻接矩阵还有前向星等等。
我们这里主要说这两种。
邻接矩阵存图:

int G[110][110],u,v,w;
for(int i = 1; i <= n; i++){
	cin >> u >> v >> w;
	G[u][v] = w;
	// G[v][u] = w;
} 

如果要建双向边,则G[v][u]也要赋值。
U是这条边的起始地,V是这条边通往的地方,W是这条边的边权。
则G[i][j]表示从 i 到 j 有一条边,边权为 w。
有人会问了,边权(Border rights)是啥?
抽象的理解就是这条边的长度。
如图:
在这里插入图片描述
可以看出1到2的路径长度为1,2到3的路径长度为2,3到1的路径长度为3。
我们继续回归正题,前向星的存图和邻接矩阵的含义大大的不同。
前向星存图:

struct node{
	int next,to;
	int val;
}a[10010];

这个代码中,next 是 i 的兄弟,也可以理解为同一层的。
to 是 i 的终点,就是 i 的下一层。
val 是 i 的边权,就是代表从 i 到 i.to 的边权。
遍历代码:

int cnt,head[10010];
void add(int u,int v,int w){
	a[++cnt].to = v;
	a[cnt].w = w;
	a[cnt].next = head[u];
	head[u] = cnt;
}

head[i]第 i 个点的层数。

例题1

B3643 图的存储(洛谷)
题目描述:
给定一个n个顶点m条边的无向图。请以邻接矩阵和邻接表的形式输出这一张图。
输入格式:
第一行输入两个正整数n和m,表示图的顶点数和边数。
第二行开始,往后m行,每行输入两个以空格隔开的正整数u,v,表示 u,v 顶点之间有一条边直接相连。
输出格式:
首先输出n行n列的矩阵,以空格隔开每一行之间的数表示邻接矩阵。第i行第j列的数为1则表示顶点i,j之间有一条边直接相连;若为0则表示没有直接相连的边。
再往后输出
n 行。第i行首先先输出一个整数di ,表示这个顶点的度数,再按照从小到大的顺序,依次输出与顶点 i 直接相连的所有顶点。
输入输出样例:
输入

5 5
1 2
2 3
3 5
1 3
3 4

输出

0 1 1 0 0
1 0 1 0 0
1 1 0 1 1
0 0 1 0 0
0 0 1 0 0
2 2 3
2 1 3
4 1 2 4 5
1 3
1 3

附上代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,u,v,d[1010],a[1010][1010];
vector<int>g[1010];
int main(){
	cin >> n >> m;
	while(m--){
		cin >> u >> v;
		g[u].push_back(v); //建双向边,从u到v
		g[v].push_back(u); //建双向边,从v到u
		d[u]++; //统计度数
		d[v]++; //两边都要
		a[u][v] = 1; //邻接矩阵存图
		a[v][u] = 1;
	}
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			cout << a[i][j] << ' ';
		}
		cout << endl;
	} //输出*1
	for(int i = 1; i <= n; i++){
		cout << d[i] << ' ';
		sort(g[i].begin(),g[i].end());
		for(int j = 0; j < g[i].size(); j++){
			cout << g[i][j] << ' ';
		}
		cout << endl;
	} //输出*2
	return 0;
}

这里对邻接表存图做一个简单的介绍。
邻接表使用vector存图,vector

连通图

连通图:就是所有点都连在一起,没有被单独存放的。
连通分量:在图中选出连通子图,就是连通分量。
强连通图:在有向图中,对于任意两个不相同的顶点,他们两个都有路径,则称强连通图。
强连通分量:在有向图中,对于任意一个子图符合上述条件,就是强连通分量。

有环图

一个图只要可以无限被走下去就是有环图(对于有向图而言)

例题2

P3916 图的遍历(洛谷)
题目描述:
给出N个点,M条边的有向图,对于每个点 v,求A(v),A(v) 表示从点 v 出发,能到达的编号最大的点。
输入格式:
第1行 2个整数 N,M 表示点数和边数。
接下来M行,每行2个整数Ui,Vi,表示边(Ui,Vi)。点用1,2,…,N编号。
输出格式:
一行N个整数A(1),A(2),…,A(N)。
输入输出样例:
输入:

4 3
1 2
2 4
4 3

输出:

4 4 3 4

附上代码:

#include<bits/stdc++.h>
const int N = 1e5 + 10;
using namespace std;
int n,m,a[N];
vector<int>E[N];
void dfs(int x,int k)	{
	if(a[x]) return;
	a[x] = k;
	for	(int i = 0;	i < E[x].size(); i++) dfs(E[x][i],k);
}
int main(){
	scanf("%d%d",&n,&m);
	while(m--){
		int x,y;
		scanf("%d%d",&x,&y);
		E[y].push_back(x);
	}
	for	(int i = n;	i; i--) dfs(i,i);
	for	(int i = 1;	i <= n;	i++) printf("%d ",a[i]);
	return 0;
}

束语

感谢大家对我C++结构体(STRUCT)的支持。
今天我们就讲到这里,拜拜!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值