动态规划-树形DP

news2024/11/25 15:33:13

树的重心

题目

链接:https://www.acwing.com/problem/content/848/

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

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

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

输入格式

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

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

输出格式

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

数据范围

1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105

输入样例

9
1 2
1 7
1 4
2 8
2 5
4 3
3 9
4 6

输出样例:

4

思路

任取一点u,如果以u为重心,则分为如下两类:

  • u的子树
  • u上面的部分

需要算出这两者的节点数,取最大值。具体细节见代码

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 1e5 + 10;
vector<int> e[N];
int n;
int sz[N]; //记录u的最大子树的节点数
int ans = 1e9;

void dfs(int u, int fa) { //u:当前点,fa:父节点
    sz[u] = 1;
    int mx = 0; //记录u上面的点和子节点连通块的最大值
    for (auto j: e[u]) {
        if (j == fa) continue; //防止向上搜索
        dfs(j, u);
        sz[u] += sz[j];
        mx = max(mx, sz[j]);
    }
    mx = max(mx, n - sz[u]);
    ans = min(ans, mx);
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n;
    for (int i = 1; i <= n - 1; i++) {
        int x, y;
        cin >> x >> y;
        e[x].push_back(y);
        e[y].push_back(x);
    }
    dfs(1, 0);
    cout << ans << endl;
    return 0;
}

树的最长直径

题目

链接:https://www.acwing.com/problem/content/1074/

给定一棵树,树中包含 $ n $ 个结点(编号$ 1   ~   n $)和 $ n-1 $ 条无向边,每条边都有一个权值。

现在请你找到树中的一条最长路径。

换句话说,要找到一条路径,使得使得路径两端的点的距离最远。

注意:路径中可以只包含一个点。

输入格式

第一行包含整数 $ n $。

接下来 $ n-1 $ 行,每行包含三个整数 $ a_i,b_i,c_i $,表示点 $ a_i $ 和 $ b_i $ 之间存在一条权值为 $ c_i $ 的边。

输出格式

输出一个整数,表示树的最长路径的长度。

数据范围

$ 1 \le n \le 10000 $,
$ 1 \le a_i,b_i \le n $,
$ -10^5 \le c_i \le 10^5 $

输入样例:

6
5 1 6
1 4 5
6 3 9
2 6 8
6 1 7

输出样例:

22

思路

任取一点u,从u点向下搜索,返回时收集边的权值,记录两条路径:

  • d1:记录从u点往下走的最长路径的长度
  • d2:记录从u点往下走的次长路径的长度

更新答案:ans=max(ans,d1+d2)

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 10010;
int n, ans;
typedef struct edge {
    int v, w;
} edge;

vector<edge> e[N];

int dfs(int u, int fa) {
    int d1 = 0, d2 = 0;//最长和次长
    for (auto j: e[u]) {
        auto [v, w] = j;
        if (v == fa) continue;
        int d = dfs(v, u) + w;
        if (d >= d1) d2 = d1, d1 = d;
        else if (d > d2) d2 = d;
    }
    ans= max(ans,d1+d2);
    return d1;
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n;
    for (int i = 1; i < n; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        e[a].push_back({b, c});
        e[b].push_back({a, c});
    }

    dfs(1, 0);
    cout << ans << endl;
    return 0;
}

树的中心

题目

链接:https://www.acwing.com/problem/content/1075/

给定一棵树,树中包含 $ n $ 个结点(编号$ 1   ~   n $)和 $ n-1 $ 条无向边,每条边都有一个权值。

请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。

输入格式

第一行包含整数 $ n $。

接下来 $ n-1 $ 行,每行包含三个整数 $ a_i,b_i,c_i $,表示点 $ a_i $ 和 $ b_i $ 之间存在一条权值为 $ c_i $ 的边。

输出格式

输出一个整数,表示所求点到树中其他结点的最远距离。

数据范围

$ 1 \le n \le 10000 $,
$ 1 \le a_i,b_i \le n $,
$ 1 \le c_i \le 10^5 $

输入样例:

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

输出样例:

2

思路

开一个数组p:p[u]记录从u点向下走点最长路径是从哪个点下去的

image.png

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 100010;
int ans = 2e9;
int n;
typedef struct edge {
    int v, w;
} edge;

vector<edge> e[N];
int d1[N], d2[N], up[N], p[N];

void dfs1(int x, int fa) {
    for (auto item: e[x]) {
        int y = item.v, w = item.w;
        if (y == fa) continue;
        dfs1(y, x);
        if (d1[y] + w > d1[x]) {
            d2[x] = d1[x], d1[x] = d1[y] + w, p[x] = y;
        } else if (d1[y] + w > d2[x]) d2[x] = d1[y] + w;
    }
}

void dfs2(int x, int fa) {
    for (auto item: e[x]) {
        int y = item.v, w = item.w;
        if (y == fa)continue;
        else if (y == p[x]) up[y] = max(up[x], d2[x]) + w;
        else up[y] = max(up[x], d1[x]) + w;
        dfs2(y, x);
    }
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n;
    for (int i = 1; i <= n - 1; i++) {
        int a, b, c;
        cin >> a >> b >> c;
        e[a].push_back({b, c});
        e[b].push_back({a, c});
    }
    dfs1(1, 0);
    dfs2(1, 0);
    for (int i = 1; i <= n; i++) {
        ans = min(ans, max(d1[i], up[i]));
    }
    cout<<ans<<endl;


    return 0;
}

数字转换

题目

链接:https://www.acwing.com/problem/content/1077/

如果一个数 $ x $ 的约数之和 $ y $(不包括他本身)比他本身小,那么 $ x $ 可以变成 $ y , , y $ 也可以变成 $ x $。

例如,$ 4 $ 可以变为 $ 3 , , 1 $ 可以变为 $ 7 $。

限定所有数字变换在不超过 $ n $ 的正整数范围内进行,求不断进行数字变换且不出现重复数字的最多变换步数。

输入格式

输入一个正整数 $ n $。

输出格式

输出不断进行数字变换且不出现重复数字的最多变换步数。

数据范围

$ 1 \le n \le 50000 $

输入样例:

7

输出样例:

3

样例解释

一种方案为:$ 4 \to 3 \to 1 \to 7 $。

思路

因为每个数x的约数之和y是固定的,但是一个约数之和y有可能是很多数x产生的,因此我们可以从yx连边,这样就可以构成一棵树了,反之就不会构成树

这样建图的方式会构造出很多的树

如何求每个数的约数:

可以使用试除法求约数,这样的时间复杂度为 O ( n n ) O(n\sqrt{n}) O(nn )本题应该可以过

也可以利用晒法的思想,对于一个数x,去枚举它的倍数(2倍,3倍…),把这些倍数的数都加上数x,这样做的时间复杂度为调和级数 l n n + C lnn+C lnn+C,因此时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

构造完树之后,求最多的变换次数即变成了求树的最长直径,可以参考代码模版。

代码

#include <bits/stdc++.h>

#define int long long
using namespace std;

const int N = 5e4 + 10;

vector<int> e[N];
int res = 0;
int d1[N], d2[N];
bool st[N];
int n;
int sum[N];

void dfs(int x, int fa) {
    for (auto y: e[x]) {
        if (y == fa) continue;
        dfs(y, x);
        if (d1[y] + 1 > d1[x]) d2[x] = d1[x], d1[x] = d1[y] + 1;
        else if (d1[y] + 1 > d2[x]) d2[x] = d1[y] + 1;
    }
    res = max(res, d1[x] + d2[x]);
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("test.in", "r", stdin);
    freopen("test.out", "w", stdout);
#endif
    cin >> n;
    //统计每个数的约数之和
    for (int i = 1; i <= n; i++) {
        for (int j = 2; j <= n / i; j++) {
            sum[i * j] += i;
        }
    }
    //建图
    for (int i = 2; i <= n; i++) {
        if (sum[i] < i) {
            e[sum[i]].push_back(i);
            st[i] = true;
        }
    }
    for (int i = 1; i <= n; i++)
        if (!st[i]) dfs(i, i);
    cout << res << endl;
    return 0;
}

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

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

相关文章

免费使用GPT4.0?搭载多模态的全新New Bing开放使用教程

目录 1 微软发布新必应2 支持文本生成图像3 支持多模态回答4 历史记录和回答导出5 支持插件化导入 1 微软发布新必应 5月4日&#xff0c;微软基于ChatGPT的搜索引擎New Bing发布了一次大规模更新&#xff0c;并宣布已开放给所有用户&#xff0c;现在无需再排队等待&#xff0c…

实力上榜!ONES 荣获深圳市「专精特新」企业认定

近日&#xff0c;ONES 成功入选 2022 年深圳市专精特新中小企业名单&#xff0c;这标志着 ONES 在研发管理领域专业化、企业数字化程度、质量管理水平、研发创新水平等多个方面得到充分认可和肯定。 深圳市专精特新企业评选是以工业和信息化部、国家统计局、国家发展改革委、财…

Live800:客服系统知识库建设中需要注意的三个要点

互联网的快速发展&#xff0c;让客服行业也随之发生着巨大的变化。传统的客服方式越来越难以满足人们的需求&#xff0c;客户对客服的要求也变得越来越高。在这种情况下&#xff0c;客服系统成为了一种必不可少的工具。 客服系统作为企业与客户沟通的重要渠道&#xff0c;其之所…

聚观早报 | 微软Build开发者大会开幕;阿里云智能裁员7%

今日要闻&#xff1a;微软Build开发者大会开幕&#xff1b;阿里云智能裁员7%&#xff1b;亚马逊中国宣布停止应用商店服务&#xff1b;苹果汽车项目启动已近10年&#xff1b;阿迪达斯中国将重新出售YEEZY系列 微软Build开发者大会开幕 5 月 24 日消息&#xff0c;继两周之前谷…

linux怎么重置密码,CentOS忘记密码,怎么重置密码

1、打开虚拟机 2、在这个界面按 e 进入到这个界面 3、下滑到这个地方&#xff0c;添加这部分代码 init/bin/sh (手动输入&#xff0c;虚拟机算是另一台电脑&#xff0c;复制不过去的) 4、填写完成后按 ctrlx 引导启动 5、输入 mount -o remount, rw / 输入 passwd xxx PS…

Jenkins+GitLab+Docker搭建前端自动化构建镜像容器部署(无本地证书,映射证书)

前言 &#x1f680; 需提前安装环境及知识点&#xff1a; 1、Docker搭建及基础操作 2、DockerFile文件描述 3、Jenkins搭建及基础点 &#x1f680; 目的&#xff1a; 将我们的前端项目打包成一个镜像容器并自动发布部署&#xff0c;可供随时pull访问 一、手动部署镜像及容器 1…

Blazor实战——Known框架增删改查导

本章介绍学习增、删、改、查、导功能如何实现&#xff0c;下面以商品资料作为示例&#xff0c;该业务栏位如下&#xff1a; 类型、编码、名称、规格、单位、库存下限、库存上限、备注 1. 前后端共用 1.1. 创建实体类 在KIMS项目Entities文件夹下创建KmGoods实体类该类继承Ent…

一个程序最多能占用的内存大小

因为内存资源总是稀缺的&#xff0c;即便在拥有百 G 内存的机器上&#xff0c;我们都可以轻易把内存填满。为了解决这个问题&#xff0c;就需要用到虚拟化技术。 GC 是面试的高频重点知识&#xff0c;同时也是程序员日常开发需要理解的部分。学习 GC 有助于你优化你开发应用的性…

1分钟用上ChatGPT,国内用户福音

众所周知的原因&#xff0c;要想在国内使用ChatGPT&#xff0c;肯定是要“折腾一番”的。 但是对于绝大多数普通小白&#xff0c;有没有比较容易的方法就用上官方的ChatGPT呢&#xff1f; 是可以的 最简单的方法就是调用OpenAI官方的API接口 就可以用“曲线救国”的方式用上…

免费部署你的私人 ChatGPT 网页应用

免费部署你的私人 ChatGPT 网页应用 1、注册Github账号&#xff0c;拷贝仓库 第一步、打开GitHub官网&#xff0c;点击右上角Sign up注册即可 第二步、打开开源项目【Chatgpt-next-web】,点击fork&#xff0c;点击Create fork完成操作 2、选择免费的容器【vercel】或者【r…

AI新晋“顶流”ChatGPT将对财务数字化带来哪些影响?

近期ChatGPT持续火热&#xff0c;2个月内&#xff0c;成为最快达成月活超过1亿的现象级应用。无论是科研人员、技术人员还是普通大众都对此非常关注&#xff0c;并惊讶于它强大的对话能力&#xff0c;ChatGPT也在国内持续霸榜热搜&#xff0c;成为大家茶余饭后的热点话题。毫无…

Mentor Pads中的关键技巧和工作方法

凡是从事电子设计的PCB工程师&#xff0c;都会知道在PCB设计工作中提高效率和质量的重要性&#xff0c;只有合理运用EDA软件的关键技巧和工作方法&#xff0c;可加速PCB设计流程&#xff0c;降低错误率&#xff0c;确保项目的成功交付。本文将以Mentor Pads软件为例&#xff0c…

Qt5安装及组件选择(Qt 5.12)

Qt5安装及组件选择&#xff08;Qt 5.12.0&#xff09; 如下图所示&#xff0c;安装Qt时有选择组件这一步&#xff0c;全部安装未免太占磁盘控件&#xff0c;只需安装我们所需要的组件即可。接下来就分析分析各个组件的作用及含义。 “Qt 5.12.0”节点下面是 Qt 的功能模块&a…

红黑树封装set和map(插入部分)

文章目录 前言1.设计大致思路2.改造封装红黑树1.插入节点2.迭代器的实现 3.map和set的封装1.代码实现2.简单测试 前言 之前我们实现了红黑树的插入的部分&#xff0c;本文主要介绍将之前实现的红黑树封装成map和set。我们是以学习的角度来封装容器&#xff0c;不用非要把库中容…

FPGA采集CameraLink相机Base模式解码输出,附带工程源码和技术支持

目录 1、前言2、CameraLink协议基础3、目前我已有的CameraLink收发工程4、设计方案输入CameraLink相机LVDS视频解码视频缓存视频输出软件配置 5、vivado工程详解6、上板调试验证7、福利&#xff1a;工程代码的获取 1、前言 FPGA实现CameraLink视频编解码目前有两种方案&#x…

华为OD机试真题 Java 实现【分界线】【2023Q1 100分】

一、题目描述 电视剧《分界线》里面有一个片段&#xff0c;男主为了向警察透露案件细节&#xff0c;且不暴露自己&#xff0c;于是将报刊上的字剪切下来&#xff0c;剪拼成匿名信。现在有一名举报人&#xff0c;希望借鉴这种手段&#xff0c;使用英文报刊完成举报操作。 但为…

day15 - 使用图像金字塔进行图像拼接

在我们之前的学习过程中&#xff0c;使用的都是恒定大小的图像&#xff0c;但是在某些情况下&#xff0c;我们需要使用不同分辨率的&#xff08;相同&#xff09;图像。例如&#xff0c;当在图像中搜索某些东西&#xff08;例如人脸&#xff09;时&#xff0c;我们不确定对象将…

vim各模式下常见指令集

vim简介 vim其实就是一款写代码的软件或者编辑器。vs2019能够编写编译调试运行代码&#xff0c;它的功能非常的集成&#xff0c;因此它被称为集成开发环境。但是vim只是编辑&#xff0c;他的核心工作就是文本编写&#xff0c;就是单纯写代码&#xff0c;因此它的功能是不集成的…

chatgpt赋能python:Python概览:了解Python的优势和应用领域

Python概览&#xff1a;了解Python的优势和应用领域 介绍Python Python是一门高级编程语言&#xff0c;由Guido van Rossum在1989年创建&#xff0c;旨在提高开发人员的开发效率和代码质量。Python有着良好的代码可读性和简洁性&#xff0c;因此它已成为全球最受欢迎的编程语…

如何在 IDEA 中生成 Maven 依赖关系图?

文章目录 1、查看依赖关系图2、保存至本地查看3、exclude IDEA提供了查看依赖关系的方式&#xff0c;如下&#xff1a; 1、查看依赖关系图 点击IDEA右侧的maven工具栏&#xff0c;展开maven操作界面。 进入maven操作界面&#xff0c;点击查看maven之间的依赖关系按钮 然后就可…