树与图的深度优先遍历(dfs的图论中的应用)

news2024/11/16 0:00:27

模板题

846. 树的重心

给定一颗树,树中包含 nn 个结点(编号 1∼n)和 n−1条无向边。

请你找到树的重心,并输出将重心删除后,剩余各个连通块中点数的最大值。

重心定义:重心是指树中的一个结点,如果将这个点删除后,剩余各个连通块中点数的最大值最小,那么这个节点被称为树的重心。

输入格式

第一行包含整数 n,表示树的结点数。

接下来 n−1行,每行包含两个整数 a 和 b,表示点 a 和点 b 之间存在一条边。

输出格式

输出一个整数 m,表示将重心删除后,剩余各个连通块中点数的最大值。

数据范围

1≤n≤10^5

输入样例
9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6
输出样例:
4

这道题的比较坑的点是题意很难理解,拿测试用例举例:

拿两个节点1和4举例,先看节点1

如果把节点1拿掉,那么剩余的联通块2、4、7点数分别是:3、4、1,那么删除节点1后连通块点数的最大值就是4

把节点4拿掉,剩余的连通块就是 :1、3、6,当中的点数分别是:5、2、1,那么删除节点4后剩余连通块节点数的最大值就是5

就这样一直找下去,那么值最小的就是重心,因为出题人偷懒重心有可能有多个不好判断对错,他就改成输出了删除重心后连通块点数的最大值

代码:

#include <iostream>
#include <vector>

using namespace std;

const int N = 1e5 + 10;
bool st[N];
vector<int> e[N];

int n;
int res = 0x3f3f3f3f;

int dfs(int u){
    st[u] = true;
    
    int size = 0,sum = 1;
    for(auto x : e[u]){
        if(st[x]) continue;
        
        int t = dfs(x);
        size = max(size,t);
        sum += t;
    }
    
    size = max(size,n - sum);
    res = min(res,size);
    
    return sum;
}

int main()
{
    cin >> n;
    for(int i = 0,a,b;i < n - 1;i ++){
        cin >> a >> b;
        e[a].push_back(b),e[b].push_back(a);
    }
    
    dfs(1);
    
    cout << res << endl;
    
    return 0;
}

树的直径

题目描述

给定一棵 n 个结点的树,树没有边权。请求出树的直径是多少,即树上的最长路径长度是多少。

输入格式

第一行输入一个正整数 n,表示结点个数。

第二行开始,往下一共 n−1 行,每一行两个正整数 (u,v),表示一条边。

输出格式

输出一行,表示树的直径是多少。

输入输出样例

输入 #1复制

5
1 2
2 4
4 5
2 3

输出 #1复制

3

说明/提示

数据保证,1≤n≤10^5。

这道题的思路是,随便从一个点出发(我是从1找的)然后找到最底下的点记为target,这个点一定是树的某一边的最下面,那么从target开始,它能到达的最远位置就是直径了

代码:

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

const int N = 1e5 + 10;
bool st[N];
vector<int> e[N];

int n;
int max_dep = 0,target = 1;

void dfs1(int u,int dep)
{
    st[u] = true;

    if(dep > max_dep){
        max_dep = dep;
        target = u;
    }

    for(auto x : e[u]){
        if(st[x]) continue;
        dfs1(x, dep + 1);
    } 
}

int dfs2(int u){
    st[u] = true;

    int sum = 0;
    for(auto x : e[u]){
        if(st[x]) continue;

        sum = max(sum,dfs2(x) + 1);
    }

    return sum;
}

int main()
{
    cin >> n;
    for(int i = 0,a,b;i < n - 1;i ++){
        cin >> a >> b;
        e[a].push_back(b),e[b].push_back(a);
    }

    dfs1(1,0);

    // cout << target << endl;

    memset(st,false,sizeof(st));

    cout << dfs2(target) << endl;

    return 0;
}

核心城市

题目描述

X 国有 n 座城市,n−1 条长度为 1 的道路,每条道路连接两座城市,且任意两座城市都能通过若干条道路相互到达,显然,城市和道路形成了一棵树。

X 国国王决定将 k 座城市钦定为 X 国的核心城市,这 k 座城市需满足以下两个条件:

  1. 这 k 座城市可以通过道路,在不经过其他城市的情况下两两相互到达。
  2. 定义某个非核心城市与这 k 座核心城市的距离为,这座城市与 k 座核心城市的距离的最小值。那么所有非核心城市中,与核心城市的距离最大的城市,其与核心城市的距离最小。你需要求出这个最小值。

输入格式

第一行 2 个正整数 n,k。

接下来 n−1 行,每行 2 个正整数 u,v 表示第 u 座城市与第 v 座城市之间有一条长度为 1 的道路。

数据范围:

  • 1≤k<n≤10^5
  • 1≤u,v≤n,u≠v,保证城市与道路形成一棵树。

输出格式

一行一个整数,表示答案。

输入输出样例

输入 #1复制

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

输出 #1复制

1

说明/提示

【样例说明】

钦定 1,2,5这 3 座城市为核心城市,这样 3,4,6 另外 3 座非核心城市与核心城市的距离均为 1,因此答案为 1。

这道题是树的直径的应用,首先题目要找到k个核心城市,那么我们先拆分问题,如果只要一个核心城市应该找那个?是不是应该找中心点(也就是树的直径的中点),这样是不是距离就一定是最小值,那么如果再找剩余的k - 1个呢?由于题目是找最小值,那么我们只要求出前k个最大的距离,然后遍历后n - k个距离就是答案了

我们以一棵树举例

算出直径是5后,找中心点

确定1是中心点,那么我们可以先算出每个点的深度(蓝色)

其次在算出每个点能达到的最大深度(紫色)

发现规律了吗?中心点的与非核心城市的距离一定是最大的,其次我们找出前k个与非核心城市距离大的点选做核心城市,然后从非核心城市当中算一下距离即可

代码:

#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 1e5 + 10;
int deep[N],dist[N],f[N];
bool st[N];
vector<int> path,e[N];


int n, k;
int l = 1, r = 1, max_dep = 0;
int D = 0,center;

void dfs1(int u, int dep) {
    st[u] = true;
    if (max_dep < dep) {
        max_dep = dep;
        l = u;
    }

    for (auto x : e[u]) {
        if (st[x]) continue;
        dfs1(x, dep + 1);
    }
}

void dfs2(int u, int d) {
    st[u] = true;
    if (D < d) D = d, r = u;

    for (auto x : e[u]) {
        if (st[x]) continue;
        dfs2(x, d + 1);
    }
}

void find(int u, int target){
    st[u] = true;
    path.push_back(u);

    if(u == target) return;

    for(auto x : e[u]){
        if(st[x]) continue;

        find(x,target);

        if(path.back() == target) return;
    }

    path.pop_back();
}

void bfs(int u)
{
    memset(deep,-1,sizeof(deep));
    deep[u] = 0;
    queue<int> q;
    q.push(u);

    while(!q.empty()){
        auto v = q.front();
        q.pop();

        for(auto x : e[v]){
            if(deep[x] == -1){
                deep[x] = deep[v] + 1;
                q.push(x);
            }
        }
    }
}

int dfs(int u){
    st[u] = true;
    int sum = deep[u];

    for(auto x : e[u]){
        if(st[x]) continue;

        int t = dfs(x);
        sum = max(sum,t);
    }

    dist[u] = sum;
    return sum;
}

bool cmp(int a,int b){
    return a > b;
}

int main() {
    cin >> n >> k;
    for (int i = 0, a, b; i < n - 1; i++) {
        cin >> a >> b;
        e[a].push_back(b),e[b].push_back(a);
    }

    dfs1(1, 0);

    memset(st,false,sizeof(st));
    dfs2(l, 0);
    // cout << "边界点:" << l << " " << r << endl;
    // cout << "直径:" << D << endl;

    memset(st,false,sizeof(st));
    find(l,r);
    int size = path.size();
    center = path[size / 2];
    // cout << "中间点: " << center << endl;

    bfs(center);

    memset(st,false,sizeof(st));
    dfs(center);
    for(int i = 1;i <= n;i ++) f[i] = dist[i] - deep[i];

    sort(f + 1,f + n + 1,cmp);
    // for(int i = 1;i <= n;i ++) cout << f[i] << " ";
    // cout << endl;
    int res = -1;
    for(int i = k + 1;i <= n;i ++) res = max(res,f[i] + 1);
    cout << res << endl;

    return 0;
}

加油

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

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

相关文章

RabbitMQ 高级特性——发送方确认

文章目录 前言发送方确认confirm 确认模式return 退回模式 常见面试题 前言 前面我们学习了 RabbitMQ 中交换机、队列和消息的持久化&#xff0c;这样能够保证存储在 RabbitMQ Broker 中的交换机和队列中的消息实现持久化&#xff0c;就算 RabbitMQ 服务发生了重启或者是宕机&…

【Android】浅析MVC与MVP

【Android】浅析MVC与MVP 什么是架构&#xff1f; 架构&#xff08;Architecture&#xff09;在软件开发中指的是软件系统的整体设计和结构&#xff0c;它描述了系统的高层组织方式&#xff0c;包括系统中各个组件之间的关系、依赖、交互方式&#xff0c;以及这些组件如何协同…

基于OpenCV的YOLOv5图片检测

利用OpenCV的DNN模块加载onnx模型文件进行图片检测。 1、使用的yolov5工程代码&#xff0c;调用export.py导出onnx模型。 2、下载opencv版本&#xff0c;https://opencv.org/releases/ 使用opencv版本4.5.3或以上&#xff0c;本文使用的opencv4.6.0 3、使用vc20…

4.使用 VSCode 过程中的英语积累 - View 菜单(每一次重点积累 5 个单词)

前言 学习可以不局限于传统的书籍和课堂&#xff0c;各种生活的元素也都可以做为我们的学习对象&#xff0c;本文将利用 VSCode 页面上的各种英文元素来做英语的积累&#xff0c;如此做有 3 大利 这些软件在我们工作中是时时刻刻接触的&#xff0c;借此做英语积累再合适不过&a…

STM32 使用 CubeMX 实现按键外部中断

目录 问题背景知识参考需要改什么注意尽量不要在中断函数使用 循环函数做延时中断函数中延时方法调试 问题 我想实现按钮触发紧急停止类似功能&#xff0c;需要使用按键中断功能。 背景知识 GPIO 点亮 LED。stm32cubemx hal学习记录&#xff1a;GPIO输入输出。STM32—HAL库 …

【实战篇】MySQL是怎么保证高可用的?

背景 在一个主备关系中&#xff0c;每个备库接收主库的 binlog 并执行。正常情况下&#xff0c;只要主库执行更新生成的所有 binlog&#xff0c;都可以传到备库并被正确地执行&#xff0c;备库就能达到跟主库一致的状态&#xff0c;这就是最终一致性。 但是&#xff0c;MySQL…

免费在线压缩pdf 压缩pdf在线免费 推荐简单好用

压缩pdf在线免费&#xff1f;在日常生活和工作学习中&#xff0c;处理PDF文件是常见任务。但有时PDF文件体积较大&#xff0c;给传输、存储和分享带来不便。因此&#xff0c;学习PDF文件压缩技巧十分必要。压缩PDF文件是指通过技术手段减小文件占用的存储空间&#xff0c;同时尽…

[Redis][Hash]详细讲解

目录 0.前言1.常见命令1.HSET2.HGET3.HEXISTS4.HDEL5.HKEYS6.HVALS7.HGETALL8.HMGET9.HLEN10.HSETNX11.HINCRBY12.HINCRBYFLOAT 2.内部编码1.ziplist(压缩链表)2.hashtable(哈希表) 3.使用场景4.缓存方式对比1.原⽣字符串类型2.序列化字符串类型3.哈希类型 0.前言 在Redis中&am…

CSS - 通用左边图片,右边内容,并且控制长度溢出处理模板(vue | uniapp | 微信小程序)

前言 通用模板&#xff0c;可适用于任意前端项目。 如下图所示&#xff0c;手机电脑通用。 示例代码 根据自己的需求修改即可。 <body><div class"container"><!-- 头像图片 --><img class"avatar" src"https://cdn.uviewui.com…

C++初阶学习——探索STL奥秘——标准库中的priority_queue与模拟实现

1.priority_queque的介绍 1.priority_queue中文叫优先级队列。优先队列是一种容器适配器&#xff0c;根据严格的弱排序标准&#xff0c;它的第一个元素总是它所包含的元素中最大的。 2. 此上下文类似于堆&#xff0c;在堆中可以随时插入元素&#xff0c;并且只能检索最大堆元…

学习大数据DAY59 全量抽取和增量抽取实战

目录 需求流程&#xff1a; 需求分析与规范 作业 作业2 需求流程&#xff1a; 全量抽取 增量抽取 - DataX Kettle Sqoop ... 场景: 业务部门同事或者甲方的工作人员给我们的部门经理和你提出了新的需 求 流程: 联系 > 开会讨论 > 确认需求 > 落地 需求文档( 具体…

Vue 项目中引入 Axios 详解

Vue 项目中引入 Axios 详解 在 Vue 项目中&#xff0c;axios 是一个非常流行的 HTTP 客户端&#xff0c;用于向服务器发送请求并处理响应。本文将详细说明如何在 Vue 项目中引入 Axios 插件&#xff0c;以及如何进行基本的配置&#xff0c;包括构建、配置域名、设置全局错误拦…

WEB攻防-JS项目Node.js框架安全识别审计验证绕过

知识点&#xff1a; 1、原生JS&开发框架-安全条件 2、常见安全问题-前端验证&未授权 详细点&#xff1a; 1、什么是JS渗透测试&#xff1f; 在JavaScript中也存在变量和函数&#xff0c;当存在可控变量及函数调用即可参数漏洞 2、流行的Js框架有哪些&#xff1f; …

CC1链的第二种方式-LazyMap版调用链

文章目录 CC1链的第二种方式-LazyMap版调用链LazyMap构造payloadCC1的调用链 CC1链的第二种方式-LazyMap版调用链 CC1链的第一种方式可以参考另一篇文章&#xff1a;CC1链_全网最菜的分析思路 LazyMap 在之前的CC1链中分析&#xff0c;其实是其中一种方式&#xff08;国内版本…

全面解析流量态势感知与网络性能监控:IT运维中的核心技术

在现代IT运维中&#xff0c;网络的稳定性和业务的连续性是企业赖以生存的基石。随着数字化转型的深入&#xff0c;网络流量日益复杂&#xff0c;安全威胁愈加严峻&#xff0c;运维人员不仅需要确保网络的顺畅运行&#xff0c;还必须及时发现潜在风险并快速响应。流量态势感知与…

如何查看Android设备的dpi

adb shell getprop ro.sf.lcd_density adb shell cat /system/build.prop > build_prop.txt shell cat system/build.prop 结果&#xff1a;参考&#xff1a; 如何查看Android设备的dpi_安卓 查看手机dpi-CSDN博客

ABAP-Swagger 一种公开 ABAP REST 服务的方法

ABAP-Swagger An approach to expose ABAP REST services 一种公开 ABAP REST 服务的方法 Usage 1: develop a class in ABAP with public methods 2: implement interface ZIF_SWAG_HANDLER, and register the public methods(example method zif_swag_handler~meta) 3: …

ElementUI 用span-method实现循环el-table组件的合并行功能

需要把指定列的相同数据合并起来&#xff08;项目中用的是updateTime&#xff09; 后端返回的数据格式&#xff1a; html&#xff1a; <el-tab-pane label"执行记录概览" name"fourth" v-loading"loading"><el-timeline v-if"re…

单元测试和unittest框架(超详细总结)

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 单元测试的定义 1. 什么是单元测试&#xff1f; 单元测试是指&#xff0c;对软件中的最小可测试单元在与程序其他部分相隔离的情况下进行检查和验证的工作&am…

电子烟智能化创新体验:WTK6900P语音交互芯片方案,融合频谱计算、精准语音识别与流畅音频播报

一&#xff1a;开发背景 在这个科技日新月异的时代&#xff0c;每一个细节的创新都是对传统的一次超越。今天&#xff0c;我们自豪地宣布一项革命性的融合——将先进的语音识别技术与电子烟相结合&#xff0c;通过WTK6900P芯片的卓越性能&#xff0c;为您开启前所未有的个性化…