【图论 DFS BFS】P10725 [GESP202406 八级] 最远点对|普及+

发布于:2025-04-22 ⋅ 阅读:(100) ⋅ 点赞:(0)

本文涉及的基础知识点

C++图论
C++DFS
C++BFS算法

[GESP202406 八级] 最远点对

题目描述

小杨有⼀棵包含 n n n 个节点的树,这棵树上的任意⼀个节点要么是白色,要么是黑色。

小杨想知道相距最远的一对不同颜色节点的距离是多少。

输入格式

第一行包含⼀个正整数 n n n,代表树的节点数。

第二行包含 n n n 个非负整数 a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an(对于所有的 1 ≤ i ≤ n 1\le i\le n 1in,均有 a i a_i ai 等于 0 0 0 1 1 1),其中如果 a i = 0 a_i=0 ai=0,则节点 i i i 的颜色为白色;如果 a i = 1 a_i=1 ai=1,则节点 i i i 的颜色为黑色。

之后 ( n − 1 ) (n-1) (n1) 行,每行包含两个正整数 x i , y i x_i,y_i xi,yi,代表存在一条连接节点 x i x_i xi y i y_i yi 的边。

保证输入的树中存在不同颜色的点。

输出格式

输出⼀个整数,代表相距最远的一对不同颜色节点的距离。

样例 #1

样例输入 #1

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

样例输出 #1

3

提示

样例解释

相距最远的不同颜色的一对节点为节点 2 2 2 5 5 5

数据范围

本题采用捆绑测试。

子任务编号 得分 n n n a i a_i ai 特殊条件
1 1 1 30 30 30 ≤ 1 0 5 \le 10^5 105 0 ≤ a i ≤ 1 0\le a_i\le 1 0ai1 树的形态为一条链
2 2 2 30 30 30 ≤ 1 0 3 \le 10^3 103 0 ≤ a i ≤ 1 0\le a_i\le 1 0ai1
3 3 3 40 40 40 ≤ 1 0 5 \le 10^5 105 0 ≤ a i ≤ 1 0\le a_i\le 1 0ai1

对于全部数据,保证有 1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1n105 0 ≤ a i ≤ 1 0\le a_i\le 1 0ai1

图论 树

转成以0为根的有根树。c[i]记录 i子树白色节点到i最远距离,d[i]记录i子树黑色节点到i的最远距离。如果不存在白色(黑色)节点,其值为-N。
DFS逻辑:
如果i是黑色节点 d[i]=0,否则c[i]=0。
d[i] = max(d[i] ,子树d[i]+1) ci类似。

ans = max(ans, c[j] + d[next] + 1);
							ans = max(ans, d[j] + c[next] + 1);
							c[j] = max(c[j], c[next] + 1);
							d[j] = max(d[j], d[next] + 1);

代码

核心代码

#include <iostream>
#include <sstream>
#include <vector>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<string>
#include<algorithm>
#include<functional>
#include<queue>
#include <stack>
#include<iomanip>
#include<numeric>
#include <math.h>
#include <climits>
#include<assert.h>
#include<cstring>

#include <bitset>
using namespace std;

template<class T1, class T2>
std::istream& operator >> (std::istream& in, pair<T1, T2>& pr) {
	in >> pr.first >> pr.second;
	return in;
}

template<class T1, class T2, class T3 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) ;
	return in;
}

template<class T1, class T2, class T3, class T4 >
std::istream& operator >> (std::istream& in, tuple<T1, T2, T3, T4>& t) {
	in >> get<0>(t) >> get<1>(t) >> get<2>(t) >> get<3>(t);
	return in;
}

template<class T = int>
vector<T> Read() {
	int n;
	scanf("%d", &n);
	vector<T> ret(n);
	for(int i=0;i < n ;i++) {
		cin >> ret[i];
	}
	return ret;
}

template<class T = int>
vector<T> Read(int n) {
	vector<T> ret(n);
	for (int i = 0; i < n; i++) {
		cin >> ret[i];
	}
	return ret;
}

class CNeiBo
{
public:
	static vector<vector<int>> Two(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0)
	{
		vector<vector<int>>  vNeiBo(n);
		for (const auto& v : edges)
		{
			vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase);
			if (!bDirect)
			{
				vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase);
			}
		}
		return vNeiBo;
	}
	static vector<vector<int>> Two(int n, vector<pair<int,int>>& edges, bool bDirect, int iBase = 0)
	{
		vector<vector<int>>  vNeiBo(n);
		for (const auto& [i1,i2] : edges)
		{
			vNeiBo[i1 - iBase].emplace_back(i2 - iBase);
			if (!bDirect)
			{
				vNeiBo[i2 - iBase].emplace_back(i1 - iBase);
			}
		}
		return vNeiBo;
	}
	static vector<vector<std::pair<int, int>>> Three(int n, vector<vector<int>>& edges, bool bDirect, int iBase = 0)
	{
		vector<vector<std::pair<int, int>>> vNeiBo(n);
		for (const auto& v : edges)
		{
			vNeiBo[v[0] - iBase].emplace_back(v[1] - iBase, v[2]);
			if (!bDirect)
			{
				vNeiBo[v[1] - iBase].emplace_back(v[0] - iBase, v[2]);
			}
		}
		return vNeiBo;
	}
	static vector<vector<int>> Mat(vector<vector<int>>& neiBoMat)
	{
		vector<vector<int>> neiBo(neiBoMat.size());
		for (int i = 0; i < neiBoMat.size(); i++)
		{
			for (int j = i + 1; j < neiBoMat.size(); j++)
			{
				if (neiBoMat[i][j])
				{
					neiBo[i].emplace_back(j);
					neiBo[j].emplace_back(i);
				}
			}
		}
		return neiBo;
	}
};
class CBFSLeve {
public:
	static vector<int> Leve(const vector<vector<int>>& neiBo, vector<int> start) {
		vector<int> leves(neiBo.size(), -1);
		for (const auto& s : start) {
			leves[s] = 0;
		}
		for (int i = 0; i < start.size(); i++) {
			for (const auto& next : neiBo[start[i]]) {
				if (-1 != leves[next]) { continue; }
				leves[next] = leves[start[i]] + 1;
				start.emplace_back(next);
			}
		}
		return leves;
	}
	template<class NextFun>
	static vector<int> Leve(int N, NextFun nextFun, vector<int> start) {
		vector<int> leves(N, -1);
		for (const auto& s : start) {
			leves[s] = 0;
		}
		for (int i = 0; i < start.size(); i++) {
			auto nexts = nextFun(start[i]);
			for (const auto& next : nexts) {
				if (-1 != leves[next]) { continue; }
				leves[next] = leves[start[i]] + 1;
				start.emplace_back(next);
			}
		}
		return leves;
	}
	static vector<vector<int>> LeveNodes(const vector<int>& leves) {
		const int iMaxLeve = *max_element(leves.begin(), leves.end());
		vector<vector<int>> ret(iMaxLeve + 1);
		for (int i = 0; i < leves.size(); i++) {
			ret[leves[i]].emplace_back(i);
		}
		return ret;
	};
};

class Solution {
		public:
			int Ans(const vector<int>& a, vector<pair<int, int>>& edge) {
				const int N = a.size();
				auto neiBo = CNeiBo::Two(N, edge, false, 1);
				auto leves = CBFSLeve::Leve(neiBo, { 0 });
				auto leveNodes = CBFSLeve::LeveNodes(leves);
				vector<int> c(N, -N), d(N, -N);
				int ans = 0;
				for (int i = leveNodes.size() - 1; i >= 0; i--) {
					for (const auto& j : leveNodes[i]) {
						if (a[j]) { c[j] = 0; }
						else { d[j] = 0; }
						for (const auto& next : neiBo[j]) {
							if (leves[next] < leves[j]) { continue; }
							ans = max(ans, c[j] + d[next] + 1);
							ans = max(ans, d[j] + c[next] + 1);
							c[j] = max(c[j], c[next] + 1);
							d[j] = max(d[j], d[next] + 1);
						}
					}
				}
				return ans;
			}
		};

int main() {
#ifdef _DEBUG
	freopen("a.in", "r", stdin);
#endif // DEBUG	
	int n;
	cin >> n ;
	auto a = Read<int>(n);
	auto edge = Read<pair<int, int>>(n - 1);
	auto res = Solution().Ans(a,edge);
#ifdef _DEBUG
	//printf("K=%d", K);
	//Out(a, ",a=");
	//Out(edge, ",edge=");
#endif // DEBUG	
	cout << res << endl;
	return 0;
}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。


网站公告

今日签到

点亮在社区的每一天
去签到