Tree Compass Codeforces Round 934 (Div. 2) 1944E

news/2024/7/15 16:58:12 标签: 算法, 数据结构, c++, c语言, 图论, 深度优先

Problem - E - Codeforces

题目大意:有一棵n个点的树,初始状态下所有点都是白色的,每次操作可以选择一个点u和一个距离dis,使得距离点u所有长度为dis的点变为黑色,问最少需要多少次操作能使所有点变成黑色,输出所有操作

1<=n<=2000

思路:要想操作数最少,就要使每次操作涂黑的点的数量尽可能多,那么也就是要找这棵树的中心点,而这样的点一定在树的直径上,也就是树上的最长链,直径可以通过两次bfs找最远点或者一次树上dp来找,这里只讲树上dp做法。

经过某个点u的最长链长度应为它的最长子链长度+次长子链长度,所以后序dfs求每个点距离叶子节点的距离的d1[u]维护最长子链的长度,d2[u]维护次长子链的长度,这样直径就等于d1[u]+d2[u]的最大值,记录取得最大值的点为根rt。

知道了直径以后还需要知道直径上的中点,所以在上述过程中用child维护每个点在最长子链中的子节点,这样从rt节点就可以向下找到中点。

如果直径的长度是偶数,也就是直径上有奇数个点,那么中点只有唯一一个,只需要在那个点处操作0到d/2的所有距离即可。

如果直径的长度是奇数,这时中点会有两个,那么如果只用其中一个点操作,操作次数将会是(d+1)/2+1,如果我们分别用两个点交叉操作,可能会出现下面这样的情况:

我们操作4 1 、4 3、5 1、5 3,只需要4次,如果只操作一个中点就需要5次,少一次的原因是我们每次操作都涂黑了至少2个点,只操作一个中点 的话必然会有只涂黑一个点的操作,而要想每次操作都涂黑至少两个点也需要直径的点数是4的倍数,这样才能两个中点交叉操作,所以只需要分两类讨论即可。

//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 2e3 + 5;
typedef long long ll;
const ll MOD = 1e9 + 7;
ll n;
vector<int>g[N];
int d1[N],d2[N];
int child[N];
int d;
int rt;
void init()
{
	for (int i = 0; i <= n; i++)
	{
		g[i].clear();
		d1[i] = 0;
		d2[i] = 0;
		child[i] = 0;
		d = 0;
		rt = 1;
	}
}
void dfs(int u, int fa)
{
	for (int i = 0; i < g[u].size(); i++)
	{
		int v = g[u][i];
		if (v == fa)
		{
			continue;
		}
		dfs(v, u);
		int temp = d1[v] + 1;//当前点到最远的叶子结点的距离
		if (temp > d1[u])
		{
			d2[u] = d1[u];//维护次长子链
			d1[u] = temp;//维护最长子链
			child[u] = v;//维护最长子链上的子节点关系
		}
		else if (temp > d2[u])
		{
			d2[u] = temp;
		}
	}
	if (d1[u] + d2[u] > d)
	{//当前点在直径上
		d = d1[u] + d2[u];
		rt = u;
	}
	
}
void solve()
{
	cin >> n;
	init();
	if (n == 1)
	{
		cout << 1 << '\n' << 1 << " " << 0 << '\n';
		return;
	}
	for (int i = 1; i < n; i++)
	{
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1, 0);
	int dif = d / 2 - d2[rt];//最长链和次长链的差
	while (dif)
	{
		rt = child[rt];//找到中心点
		dif--;
	}
	if (d % 2 == 0 || d1[rt] % 2 == 1)
	{//直径长度是偶数或者最长子链长度是奇数(这时候点数一定不是4的倍数),只用一个中点就行
		cout << (d - 1) / 2 + 1 + 1 << '\n';
		for (int i = 0; i <= d1[rt]; i++)
		{
			cout << rt << " " << i << '\n';
		}
	}
	else
	{//分别用两个中点交叉操作
		cout << d / 2 + 1 << '\n';
		int temp = d - d1[rt];
		int temp2 = temp;
		while (temp2>=0)
		{
			cout << rt << " " << temp2 << '\n';
			temp2 -= 2;
		}
		temp2 = temp;
		rt = child[rt];
		while (temp2>=0)
		{
			cout << rt << " " << temp2 << '\n';
			temp2 -= 2;
		}
	}
	//cout << '\n';
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}


http://www.niftyadmin.cn/n/5441931.html

相关文章

【MySQL】数据库的基础概念

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习计网、mysql和算法 ✈️专栏&#xff1a;MySQL学习 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac…

yank+mermaid+甘特图实例

因为notion对于mermaid支持很一般&#xff0c;尤其是甘特图&#xff0c;如果时间跨度大、节点多&#xff0c;字号会小到看不见&#xff0c;非常不方便。 同样的代码&#xff0c;在notion中如下图所示&#xff1a;&#xff08;下图是我的一份年度规划&#xff09; &#xff08;…

深度探索:SWAT模型和生物地球化学循环模型实现流域生态系统水-碳-氮耦合过程模拟

目录 专题一 流域水碳氮建模概述 专题二 ArcGIS入门 专题三 SWAT模型建模流程 专题四 DEM数据制备流程 专题五 土地利用数据制备流程 专题六 土壤数据制备流程 专题七 气象数据制备流程 专题八 农业措施数据制备流程 专题九 参数率定与结果验证 专题十 CENTURY模型建…

5G网络架构与组网部署03--5G网络组网部署

1. SA组网与NSA组网 &#xff08;1&#xff09;NSA 非独立组网&#xff1a;终端同时接入4G基站和5G基站&#xff0c;只能实现5G部分功能 &#xff08;2&#xff09;SA组网【最终目标】&#xff1a;5G基站可以单独提供服务&#xff0c;接入的是5G核心网 区别&#xff1a;同一时间…

个人开发App成功上架手机应用市场的关键步骤

目录 1. 苹果审核和APP备案 2. APP上架操作步骤 3. 审核和发布 4. 上线工作 总结 参考资料 在当前移动应用市场竞争激烈的背景下&#xff0c;个人开发App如何成功上架成为开发者们必须面对的重要任务。本文将重点介绍自建App上架至手机应用市场的流程&#xff0c;包括苹果…

Python数学建模-2.9Matplotlib库

Matplotlib库是Python中一个非常流行的绘图库&#xff0c;它提供了大量的绘图工具&#xff0c;可以生成各种类型的静态、动态、交互式的图表。Matplotlib的设计初衷是为了与NumPy配合使用&#xff0c;从而提供一个强大的数学绘图工具。 1.Matplotlib的主要特点 丰富的图表类型…

【漏洞复现】Progress Kemp LoadMaster 命令注入漏洞(CVE-2024-1212)

0x01 产品简介 Progress Kemp LoadMaster是一款高性能的应用交付控制器&#xff0c;具有可扩展性&#xff0c;支持实体硬件和虚拟机的负载均衡。它提供了当今应用服务所需的各种功能&#xff0c;包括深度用户验证、资安防护&#xff08;如WAF/IPS/DDoS防护&#xff09;以及零信…

后端系统开发之——创建注册接口

原文地址&#xff1a;后端系统开发之——创建注册接口 - Pleasure的博客 下面是正文内容&#xff1a; 前言 这是一篇SpringBoot项目的实践篇。 主要用于介绍如何从零开始搭建某一种类型的系统。 个人认为&#xff0c;只要后端逻辑完善了&#xff0c;纵使前端页面千变万化都可…