C++图笔记(三)有向无环图(及最小生成树(略))以及剩下的排序

news2024/11/14 15:44:37

目录

一,定义:

1,有向无环图

 2,拓朴排序

 1,每个顶点出现且仅仅出现一次。

 2,若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。

二,DAG的性质

性质1.   从任意一个起点进行dfs,必不会陷入死循环。

性质2.   入度为0的点信息确定,删掉入度为0的点以及出边后,新的入度为0的点信息也唯一确定。

三,拓扑排序的遍历

 四,例题

1,有向图的拓扑序列

使用图片理解拓扑排序(也是该图的模拟过程)

1,在不考虑边权的情况下 输入数据为:

由此建立邻接表。可得第一次入度为零的点为“1”“2” 将此两点入度

所以先将1指向的点和边删除,并将指向的点(3,4)的入度-1;得到下图

由于第一次入度为零的点还有“2”,将1删除后,点“2”还在队中,所以同上操作,得到图三

由上图得:点3的入度为零,所以按照操作将“3”入队,出队,删边,删除边指向的点的入读-1;

同上操作,此时删除点“4;则点“5”的入读=0;

经过删除。得到点六,所以存在拓扑排序,该图为DAG

2,求最长路

五,最小生成树

1,定义:

2,基本性质

1. 生成树是一个连通子图,是给定图的一个子集,它连接了所有节点且没有环。(有环可以减少一条边)

2. 生成树形态不止一种,且含有图中全部n个顶点,以及包含图中n-1条边。

3,求解方法:

        1、Kruskal  复杂度:n(mlogm)

        2、例题 详见下:​编辑

代码:


一,定义:

1,有向无环图

如果有一个非有向无环图,且A点出发向B经C可回到A,形成一个环。将从C到A的边方向改为从A到C,则变成有向无环图。有向无环图的生成树个数等于入度非零的节点的入度积。(from baidu)

若一个有向图不存在环,则称为有向无环图【字面意思】这个东西就叫做DAG(Directed Acyclic Graph),

如图所示:

 2,拓朴排序

在图论中,拓扑排序(Topological Sorting)是一个有向无环图的所有顶点的线性序列。且该序列必须满足下面两个条件:

 1,每个顶点出现且仅仅出现一次


 2,若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。

由拓朴排序的定义可知:只有DAG才有拓扑排序,其余没有拓扑排序一说。

二,DAG的性质

性质1.   从任意一个起点进行dfs,必不会陷入死循环。


性质2.   入度为0的点信息确定,删掉入度为0的点以及出边后,新的入度为0的点信息也唯一确定。

三,拓扑排序的遍历

在dij和spfa等算法中,任意点都会重复更新多次,所以会导致时间复杂度提高。在拓扑排序中,不是从起点(任意点)开始遍历,而是从入度为0的点开始遍历,这样该点就不会有其它点进行更新它。所以这样每个点和边都只会被遍历一次。

所以拓朴排序的时间复杂度为n(n+m).

拓扑排序的大致过程:

  1. 从 图中选择一个 入度为0的顶点并入度。
  2. 当该节点出队时,将该节点所指向边的节点入度-1如果新节点入度为零,则将新节点入度。
  3. 重复 1 和 2 直到当前图为空或当前图中不存在入度为零的顶点为止。后一种情况说明有向图中必然存在环。当所有节点都入过队列,则当前图存在拓扑排序,则该图为DAG图。

 四,例题

1,有向图的拓扑序列

题目:(要求详见图)

使用图片理解拓扑排序(也是该图的模拟过程)

1,在不考虑边权的情况下 输入数据为:
6 7(点数,边数)
1 3
1 4
2 5
4 5
3 6
5 6
3 4

由此建立邻接表。可得第一次入度为零的点为“1”“2” 将此两点入度

所以先将1指向的点和边删除,并将指向的点(3,4)的入度-1;得到下图

 

由于第一次入度为零的点还有“2”,将1删除后,点“2”还在队中,所以同上操作,得到图三

由上图得:点3的入度为零,所以按照操作将“3”入队,出队,删边,删除边指向的点的入读-1;

同上操作,此时删除点“4;则点“5”的入读=0;

经过删除。得到点六,所以存在拓扑排序,该图为DAG

在删除边的过程中,将出队但未被删除的点存入一个vector容器。最后将该容器按照顺序输出则得到了该图的拓扑排序。

如果该容器中存下的点的数量 不等于一开始输入的点的数量,则该图不存在拓扑排序,即该图不是DAG图。

#include<bits/stdc++.h>//万能头
#pragma GCC s//日常优化
#pragma GCC optimize(2)//相信肯定有人要借鉴代码,这可不是好习惯哦,所以注释++++++
#pragma GCC optimize(3)
#pragma GCC fast

using namespace std;

const int N = 2e5 + 100;//提前定义节省时间
const int M = 4e5 + 100;
int head[N], Next[M], ver[M], tot,deg[N],n,m;

void add(int x, int y) {//建立邻接表
    ver[++tot] = y;
    Next[tot] = head[x];
    head[x] = tot;
}

long long read() {//日常快读,节省时间
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}

vector<int>v;	
priority_queue<int,vector<int>,greater<int> > qc;//因为题目要求按照字典序最小输出,所以建立优先队列
void topsort() {//拓朴排序
    for (int i=1;i<=n;i++)
        if (!deg[i])            qc.push(i);        
    while (qc.size()) {
        int x = qc.top(); qc.pop();
       	v.push_back(x);//在出队时进行记录
        for (int i = head[x];i;i=Next[i]) {
            int y=ver[i];
            if (!--deg[y])            qc.push(y);
        }    
	}
}

int main() {
    int x, y;
    n=read();m=read();//运用快读(点的个数,边的个数)
    for (int i=1;i<=m;i++) {
        x=read();y=read();//快读+2
        add(x,y);
        deg[y]++;//将被指向的结点入度加1
    }
    topsort();//开始排序
    if (v.size()<n)//如果有的点没有被遍历过说明不存在拓扑排序,即不存在DAG
        cout <<-1;
    else {
    	for(int i=0;i<v.size();i++)		cout<<v[i]<< " ";
	}
    return 0;
}

2,求最长路

题目见图++;

题目分析:如果按照常规操作,这道题肯定要TLE,另外,数据范围也要注意(开小了PAC)所以,这道题只能快读+拓扑排序才能过

#include<bits/stdc++.h>//万能头文件
#pragma GCC s//O优化
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC fast

using namespace std;
const int N=5e5+5,M=3e6+5;//根据题目范围提前定义
int head[N], Next[M],ver[M],du[N],dis[M],w[M],tot,n,m;//关于结点的范围是N,和边有关的大小为M;

long long read() {//快读
	int x=0,f=1;
	char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) {
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
void add(int x, int y,int z) {//建立邻接表
	++tot;
    ver[tot]=y;
    w[tot]=z;
    Next[tot]=head[x];
    head[x]=tot;
}
void bfs() {//开始遍历
	queue<int>q;
    for (int i=1;i<=n;i++) {   
        if(!du[i])q.push(i);
		dis[i]=-2e9;
	}
	dis[1]=0;
    while (!q.empty()) {
        int x=q.front();//存下来要遍历的节点
		q.pop();//将该节点出队
        for (int i = head[x];i;i=Next[i]) {
            int y=ver[i];
            du[y]--;
            if(dis[x]!=-2e9){
            	dis[y]=max(dis[y],dis[x]+w[i]);
			}
			if(!du[y]) {
				q.push(y);//将节点入队,等待重新遍历
			}
        }    
	}
}
int main() {
    int x,y,z;
    n=read();//使用快读
    m=read();
    for(int i=1;i<=m;i++) {
    	x=read();//源节点
     	y=read();//指向的节点
      	z=read();//边权
        add(x,y,z);
        du[y]++;//被指向的节点入度++
    }
    bfs();
    cout<<dis[n];//输出最大路径
    return 0;
}

五,最小生成树

1,定义:

最小生成树(Minimum Spanning Tree,MST)是指在连通图的所有生成树中,各边的权值之和最小的生成树。它是一个连通的无向图,其中所有顶点都连通,且没有环,边的权值之和最小。生成树是在无向连通图中,将图中所有顶点以最少的边连通的子图。即建图转化为树,用最少的边保证每个节点的连通性。

2,基本性质

1. 生成树是一个连通子图,是给定图的一个子集,它连接了所有节点且没有环。(有环可以减少一条边)


2. 生成树形态不止一种,且含有图中全部n个顶点,以及包含图中n-1条边。

3,求解方法:

        1、Kruskal  复杂度:n(mlogm)

        2、例题 详见下:

代码:

#include<bits/stdc++.h>//万能头文件
#pragma GCC optimize(1)//O优化
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma Gcc optinize("o1")
#pragma Gcc optinize("o2")
#pragma Gcc optinize("o3")
#pragma GCC optimize("Ofast")
using namespace std;
const int N  =2e5+5;
int n,m,mst=0,fa[N],cnt=0;//记录长度之和
struct node{//运用结构体来存边,按照边权大小进行排序
	int u,v,w;
}pt[N];
long long read() {//日常快读
	int x=0,f=1;
	char c=getchar();
	while(c<'0'||c>'9') {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9') {
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
bool operator<(node x,node y){//重载一下运算符,方便进行结构体比较
	return x.w<y.w;
}
int find(int x){
	if(fa[x]==x)return  x;
	return fa[x]=find(fa[x]);
}
void kruscal(){
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=m;i++){
		int a=find(pt[i].u), b=find(pt[i].v);
		if(a!=b){
			fa[a]=b;
			mst+=pt[i].w;
			cnt++;
			
		}
		if(cnt==n-1) break;
	}
}
int main(){
	n=read();m=read();
	for(int i=1;i<=m;i++){
		int x,y,z;
		x=read();y=read();z=read();
		pt[i]={x,y,z};
	} 
	sort(pt+1,pt+m+1);
	kruscal();
	if(cnt<n-1) cout<<"orz";
	else cout<<mst;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2054630.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Clash-Docker在Ubuntu下的使用

说明 最近折腾nas&#xff0c;docker镜像被墙之后很多镜像拉取不了&#xff0c;需要添加代理&#xff0c;这里使用Clash docker版。 安装&运行 docker pull dreamacro/clash:v1.18.0 docker run -d --name clash --network host dreamacro/clash:v1.18.0修改配置文件 d…

java使用itext 直接生成pdf

itext 使用 需求背景itext 的使用依赖简单示例基础设置&#xff08;页面大小、边距、字体等&#xff09;段落内部&#xff0c;特殊设置关键字 字体或颜色生成动态表格页脚展示页数其他设置密码添加水印&#xff08;背景图&#xff09;目录Header, Footer分割 PDF合并 PDF 需求背…

动态路由//

静态路由的缺点 1.配置量大 2.不能基于拓扑的变化进行实时更新 总结:只能在简单的小型网络中进行配置 动态路由的优点 实时基于拓扑的变化而进行路由表的收敛 动态路由的缺点 1.额外的占用链路资源:动态路由协议需要路由器之间不断交换路由信息&#xff0c;这会占用网络…

在PasteSpider中使用gitee的webhook实现类似Jenkins的CI/CD持续部署

准备事宜 1.已经在PasteSpider中配置好了相关的项目和服务 2.在gitee中有创建对应的代码仓库 实现原理 1.webhook是时下非常流行的一个推送模式&#xff0c;webhook其实就是往某一个特定的地址推送消息&#xff0c;这样可以避免频繁的轮询&#xff0c;在事件发生后的第一时间告…

Microsoft Edge 使用方法与秘诀概览

目录 ​编辑引言 Microsoft Edge 功能与技巧概览 掌握这些设置技巧&#xff0c;让 Edge 浏览器的体验更干净 1. 使用阅读视图 2. 开启广告过滤 3. 管理扩展 4. 个性化新标签页 5. 使用网页截图 6. 清理浏览器缓存 7. 管理启动设置 8. 自定义地址栏建议 9. 使用内置笔…

OLAP引擎之Druid

Apache Druid 简介 Apache Druid 是一个开源的、分布式的实时分析数据库&#xff0c;专为大规模数据的快速查询和实时分析而设计。Druid 将数据存储、索引和查询处理功能结合在一起&#xff0c;支持对流数据和批量数据进行快速的、低延迟的分析查询。它特别适用于需要高并发、…

C语言内存操作函数

目录 一. C语言内存操作函数 1. memcpy的使用和模拟实现 2. memmove函数 3. memset函数 4. memcmp函数 一. C语言内存操作函数 随着知识的不断积累&#xff0c;我们所想要实现的目标程序就会更加复杂&#xff0c;今天我们来学习一个新的知识叫做C语言内存操作函数&#x…

eNSP 华为交换机生成树协议

华为交换机生成树协议 生成树协议原理与作用 选举一个交换机作为根网桥&#xff08;生成树的根&#xff09;&#xff0c;计算出到其他所有交换机的最佳路径&#xff0c;把备用路径的端口设为堵塞状态&#xff08;逻辑上关闭备用路径&#xff09;&#xff0c;当最佳路径故障再…

制造企业为什么要数字化转型?面临哪些困难?

如何界定制造企业 制造业&#xff08;Manufacturing Industry&#xff09;是指机械工业时代利用某种资源&#xff08;物料、能源、设备、工具、资金、技术、信息和人力等&#xff09;&#xff0c;按照市场要求&#xff0c;通过制造过程&#xff0c;转化为可供人们使用和利用的…

01:电容的什么,各类电容的优缺点

1.电容是什么&#xff1f; 电容是由两块不连通的导体&#xff0c;已经中间的不导电材料组成 电容结构&#xff1a; 1.2电容的容量计算公式 C ε s d \displaystyle\frac{εs}{d} dεs​ 1.3常见电容的种类 1.4各类电容的特点

【大模型从入门到精通31】开源库框架LangChain RAG 系统中的问答技术1

这里写目录标题 引言问答与语言模型一般流程整合方法 通过高级问答技术增强 RAG 系统利用 VectorDB 进行文档检索实现问答链初始化语言模型配置 RetrievalQA 链 问答实战 引言 检索增强生成 (RAG) 系统已经革新了我们与大型数据集互动的方式&#xff0c;使得开发高度复杂的聊天…

深入探索MyBatis的动态代理模式

文章目录 深入探索MyBatis的动态代理模式引言一、 MyBatis动态代理概述动态代理的优势 二、准备工作文件存放结构视图1、Mybatis的主配置文件 mybatis-config.xml2、db.properties文件:3、mybatis-config.xml引用properties文件: 三、MyBatis动态代理的实现原理1. Mapper接口定…

基于STM32F103的FreeRTOS系列(十)·消息队列的使用详细介绍以及代码编写

目录 1. 消息队列简介 1.1 概念 1.2 数据存储 1.3 阻塞机制 1.3.1 出队阻塞 1.3.2 入队阻塞 1.4 操作示意图 1.4.1 创建队列 1.4.2 向队列发送第一个消息 1.4.3 向队列发送第二个消息 1.4.4 从队列读取消息 1.5 消息队列的控制块 2. 常用API函数介绍…

android13顶部状态栏里面调节背光,不隐藏状态栏面板

总纲 android13 rom 开发总纲说明 目录 1.前言 2.代码分析 3.修改方法 4.编译运行 5.彩蛋 1.前言 android13顶部状态栏里面调节背光,这个时候状态栏面板会被隐藏掉,有些需求就需要不隐藏这个面板。 2.代码分析 查找亮度条属性 id/brightness_slider ./frameworks/b…

Vue 3 + 天地图 + D3.js 绘制行政区划

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;组件封装篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来组件封装篇专栏内容:组件封装-天地图 目录 引入天地图 API 初始化地图 引入 D3.js 加载行政区划数据 添…

k8s高版本(1,28)部署NodePort模式下的ingress-nginx的详细过程及应用案例

文章目录 前言环境ingress安装应用案例(ingress-http案例&#xff1a; 基于名称的负载均衡) 前言 这个是nodeport模式下的&#xff0c;如果需要loadbalancer模式下的&#xff0c;看看博主下面以前的博客 链接: k8s学习–负载均衡器matelLB的详细解释与安装 链接: k8s学习–ing…

机器学习 之 使用逻辑回归 进行银行贷款预测(请帮忙点点赞谢谢,这对我很重要)

目录 一、逻辑回归简介 逻辑回归的基本原理 线性组合&#xff1a; Sigmoid函数&#xff1a; 二、实战案例 1.导入数据 2.准备环境 混淆矩阵的基本概念 混淆矩阵的作用 3.加载数据 4.数据预处理 什么是标准化&#xff1f; 标准化的计算公式 划分数据集 5.逻辑回归模…

19.缓存的认识和基本使用

缓存介绍 缓存是数据交换的缓冲区Cache&#xff0c;是临时存储数据的地方&#xff0c;一般读写性能较高。 数据库的缓存就是建立索引。 缓存的作用 1.降低后端负载。 2.提高读写效率&#xff0c;降低响应时间。 缓存的问题 1.保证数据的一致性。 2.增加代码维护成本。解…

Kafka运行机制(二):消息确认,消息日志的存储和回收

前置知识 Kafka基本概念https://blog.csdn.net/dxh9231028/article/details/141270920?spm1001.2014.3001.5501Kafka运行机制&#xff08;一&#xff09;&#xff1a;Kafka集群启动&#xff0c;controller选举&#xff0c;生产消费流程https://blog.csdn.net/dxh9231028/arti…

Qt 0816作业

一、思维导图 二、将day1做的登录界面升级优化【资源文件的添加】 三、在登录界面的登录取消按钮进行一下设置 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到…