图论基础(未完成)

在这里插入图片描述

图论基本定理(握手定理):

(无向图)结点度数和 = 边数两倍
(有向图)结点入度与出度的和 = 边数
在这里插入图片描述

图的基本概念

顶点:图中的一个点,一个边的两头的顶点称为相邻的顶点
:连接两个顶点的线段叫做边
度数:由一个顶点出发,有几条边就称该顶点有几度,或者该顶点的度数是几
出度:由一个顶点出发的边的总数
入度:指向一个顶点的边的总数
头尾:有向图,一条边的出发点称为头,指向点称为尾
奇点:度数为奇数的顶点
偶点:度数为偶数的顶点
路径:通过边来连接,按顺序的从一个顶点到另一个顶点中间经过的顶点集合
简单路径:没有重复顶点的路径
:至少含有一条边,并且起点和终点都是同一个顶点的路径
简单环:不含有重复顶点和边的环
有向路径:图中一组顶点满足从其中任意一个顶点出发,都存在一条有向边指向这组顶点中的另一个
有向环:至少含有一条边的起点和终点都是同一个顶点的一条有向路径
简单有向环:一条不含有重复顶点和边的环
路径或环的长度就是路径和环包含的边数
通路:两点间连通的路径
基本通路(路径):没有重复出现的结点的通路
连通的:当从一个顶点出发可以通过至少一条边到达另一个顶点,我们就说这两个顶点是连通的
连通图:图中从任意顶点均存在一条边可以到达另一个任意顶点,我们就说这个图是个连通图
连通分量:图中连通的顶点与边的集合
权和网:在图的边给出相关的数,成为权,带权图一般成为网
最短路径:长度最短的一条通路
完全图:任何两点顶点之间都有边(弧)相连
稀疏图、稠密图:边(弧)很少的图,图中每个顶点的度数不高称为稀疏图,反之为稠密图
无环图:是一种不包含环的图
二分图:可以将图中所有顶点分为两部分的图
欧拉通路(回路):通过每条边一次且仅一次,而且走遍每个结点的通路
欧拉图:含欧拉通路的图
哈密顿通路(回路):通过每个结点一次且仅一次
哈密顿图:含哈密顿通路的图
在这里插入图片描述

图的存储

邻接矩阵

scanf("%d", &n);
for(int i = 1; i <= n; i++)
	for(int j = 1; j <= n; j++)
		scanf("%d", &a[i][j]);

邻接表

struct psx{int y, v, next} e[];
int lin[], len = 0;

void insert(int xx, int yy, int vv) {
	e[++len].next = lin[xx];
	lin[xx] = len;
	e[len].y = yy;
	e[len].v = vv;
}

void init() {
	scanf("%d%d", &n, &m);
	memset(e, 0, sizeof(e));
	memset(lin, 0, sizeof(lin));
	for(int i = 1; i <= n; i++) {
		int xx, yy, vv;
		scanf("%d%d%d", &xx, &yy, &vv);
		insert(xx, yy, vv);
		insert(yy, xx, vv);
	}
}

边表

struct psx{int x, y, v} e[];

void init() {
	scanf("%d%d", &n, &m);
	memset(e, 0, sizeof(e));
	for(int i = 1; i <= n; i++) 
		scanf("%d%d%d", &e[i].xx, &e[i].yy, &e[i].vv);
}

在这里插入图片描述

图的遍历
深宽搜(基础概念,大佬可跳过不看)

BFS

邻接矩阵代码
void bfs(int k) {
	int head = 0, tail = 1;
	q[tail] = k;
	while(head++ < tail) 
		for(int i = 1; i <= n; i++) 
			if(a[q[head]][i] && !vis[i]) {
				vis[i] = 1;
				q[++tail] = i;
			}
}
邻接表代码
void bfs(int k) {
	int head = 0, tail = 1;
	q[tail] = k;
	while(head++ < tail) 
		for(int i = lin[ q[head] ]; i ; i = e[i].next) 
			if(!vis[ e[i].y ]) {
				vis[ e[i].y ] = 1;
				q[++tail] = e[i].y;
			}
}

DFS

邻接矩阵代码
void dfs(int k) {
	for(int i = 1; i <= n; i++) 
		if(a[k][i] && !vis[i]) vis[i] = 1, dfs(i);
}
邻接表代码
void dfs(int k) {
	for(int i = lin[k]; i ; i = e[i].next) 
		if(!vis[e[i].y]) vis[e[i].y] = 1,dfs(e[i].y);
}
拓扑搜索

检查有向图是否存在回路
往拓扑序列中放入入度为 0 0 0的点,删去与它相连的边后,再往拓扑序列中放入入度为 0 0 0的点 … … ……
如果拓扑序列中放入的元素数量小于连通图中顶点的数量,则存在环

scanf("%d%d", &x, &y); deg[y]++;//输入时记录一下入度
	
int head=0, tail=0;
for(int i = 1; i <= n; i++)
	if(!deg[i]) q[++tail] = i;

//邻接表版本
while(head++ < tail) 
	for(int i = lin[q[head]]; i; i = e[i].next) {
		deg[e[i].y]--;
		if(!deg[e[i].y]) q[++tail] = e[i].y;
	}
//邻接矩阵版本
while(head++ < tail) 
	for(int i = 1; i <= n; i++) 
		if(a[q[head]][i]) {
			deg[i]--;
			if(!deg[i]) q[++tail] = i;
		}

在这里插入图片描述

图的传递闭包

判断无向图的连通性
判断 i i i j j j是否有路径
1. 1. 1.结点 i i i到结点 j j j有边
2. 2. 2.存在结点 k k k满足结点 i i i到结点 k k k有边,且结点 k k k到结点 j j j有边,则结点 i i i到结点 j j j有边

for(int i = 1; i <= n; i++) can[i][i] = 1;
for(int k = 1; k <= n; k++)
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			can[i][j] ||= (can[i][k] && can[k][j]);

在这里插入图片描述

任意两点间的最短路
Floyed算法

根据图的传递闭包的原理,复杂度O(n 3 ^{3} 3)

初始化
dis[i][i] = 0;
dis[i][j] = 边权;(有边相连)
dis[i][j] = 正无穷;(无边相连)
算法
for(int k = 1; k <= n; k++)
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			if(dis[i][k] + dia[k][j] < dia[i][j])
				dia[i][j] = dis[i][k] + dia[k][j];

输出最短路径
p a t h [ i ] [ j ] path[i][j] path[i][j]记录 i i i j j j的最短路径中 j j j的前驱结点

初始化
path[i][j] = i;(有边相连)
path[j][i] = j;(有边相连)
记录
for(int k = 1; k <= n; k++)
	for(int i = 1; i <= n; i++)
		for(int j = 1; j <= n; j++)
			if(dis[i][k] + dia[k][j] < dia[i][j]){
				dia[i][j] = dis[i][k] + dia[k][j];
				path[i][j] = k;
			}
输出
void dfs(int i, int j){
	if(path[i][j] > 0) {
		dfs(i, path[i][j]);
		cout<<path[i][j]<<" ";
		dfs(path[i][j], j);
	}
}

在这里插入图片描述

单源最短路径——Dijkstra(迪杰斯特拉算法)

如果源点到某个点 x x x的距离是到其他点的距离的最小值,那么到点 x x x的最短距离

单源,非负
用集合1表示已知点,用集合2表示未求点
则1中最初只有start一个点,集合2中有其他n-1个点
1.在集合2中找到到start距离最近的顶点k,距离=d[k]
2.把顶点k加到

void dijkstra(int st) {
	for(int i = 1; i <= n; i++) dis[i] = a[st][i];
	memset(vis, 0, sizeof(vis));
	vis[st] = 1;
	dis[st] = 0;
	for(int i = 1; i < n; i++){
		int minn = 99999999, k = 0;
		for(int j = 1; j <= n; j++)
			if(!vis[j] && dis[j] < minn)	minn = dis[j], k = j;
		if(k == 0) return;
		vis[k] = 1;
		for(int j = 1; j <= n; j++)
			if(!vis[j] && dis[k]+a[c][j] < dis[j])
				dis[j] = dis[k] + a[k][j];
	}
}

在这里插入图片描述

树的基础

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值