2024年6月GESP真题及题解(C++八级): 最远点对

2024年6月GESP真题及题解(C++八级): 最远点对

题目描述

小杨有一棵包含 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 1≤i≤n,均有 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) (n−1) 行,每行包含两个正整数 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 ≤ 10 5 \le 10^5 ≤105 0 ≤ a i ≤ 1 0\le a_i\le 1 0≤ai≤1 树的形态为一条链
2 2 2 30 30 30 ≤ 10 3 \le 10^3 ≤103 0 ≤ a i ≤ 1 0\le a_i\le 1 0≤ai≤1
3 3 3 40 40 40 ≤ 10 5 \le 10^5 ≤105 0 ≤ a i ≤ 1 0\le a_i\le 1 0≤ai≤1

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

思路分析

  1. 理解问题本质:在树上找到距离最远的两个异色节点,距离定义为节点间路径的边数。

  2. 暴力解法不可行:直接枚举所有异色节点对是 O(n²) 的,n ≤ 10⁵ 时不可行。

  3. 高效解法思路

    • 树的直径通常可以通过两次 BFS/DFS 找到最远点对
    • 但这里要求是不同颜色的节点对
    • 关键观察:最远异色节点对一定包含某个颜色的最远点之一
  4. 算法设计

    • 对于每种颜色,找到距离该颜色所有节点最远的节点
    • 从白色节点中找到距离所有黑色节点最远的点
    • 从黑色节点中找到距离所有白色节点最远的点
    • 这两个距离中的最大值就是答案
  5. 实现方法

    • 进行三次 BFS:
      1. 从任意节点开始,找到最远的节点 A
      2. 从 A 开始,记录到所有节点的距离 distA
      3. 从 B(与 A 不同颜色)开始,记录到所有节点的距离 distB
    • 答案 = max(从白色到黑色的最远距离, 从黑色到白色的最远距离)

代码实现

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;  // 最大节点数+5的缓冲区

int n;                 // 树的节点数
int c[N];              // 颜色数组,c[i]表示节点i的颜色:0-白色,1-黑色
vector<int> g[N];      // 邻接表,存储树的结构
int d[2][N];           // 距离数组,d[0][i]表示从A到i的距离,d[1][i]表示从B到i的距离

// BFS函数:从起点s开始进行广度优先搜索,计算到所有节点的距离
// 参数:s - 起点,dist - 存储距离的数组指针
// 返回值:BFS过程中最后访问的节点(即距离起点最远的节点)
int bfs(int s, int* dist) {
    queue<int> q;  // BFS队列
    
    // 初始化距离数组,将所有距离设为-1表示未访问
    fill(dist + 1, dist + n + 1, -1);
    
    // 起点距离为0,加入队列
    dist[s] = 0;
    q.push(s);
    int last = s;  // 记录最后访问的节点
    
    // BFS主循环
    while (!q.empty()) {
        int u = q.front(); q.pop();  // 取出队首节点
        last = u;  // 更新最后访问的节点
        
        // 遍历u的所有邻居
        for (int v : g[u]) {
            // 如果邻居v尚未访问过
            if (dist[v] == -1) {
                dist[v] = dist[u] + 1;  // 更新距离
                q.push(v);              // 加入队列
            }
        }
    }
    
    return last;  // 返回最后访问的节点(即最远节点)
}

int main() {
    // 输入输出优化
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    // 读入节点数
    cin >> n;
    
    // 读入每个节点的颜色
    for (int i = 1; i <= n; i++) cin >> c[i];
    
    // 读入树的边,构建邻接表
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    
    // 第一步:第一次BFS,从任意节点(节点1)出发,找到最远点A
    int A = bfs(1, d[0]);
    
    // 第二步:第二次BFS,从A出发,找到最远点B
    // 同时,d[0]数组现在存储的是从A到所有节点的距离
    int B = bfs(A, d[0]);
    
    // 第三步:第三次BFS,从B出发
    // d[1]数组将存储从B到所有节点的距离
    bfs(B, d[1]);
    
    // 现在我们有:
    // d[0][i] - 从A到节点i的距离
    // d[1][i] - 从B到节点i的距离
    
    int ans = 0;  // 存储最终答案(最远异色节点对的距离)
    
    // 情况1:考虑以A为端点的最远异色节点对
    // 遍历所有节点,找到与A颜色不同的节点,更新最大距离
    for (int i = 1; i <= n; i++) {
        if (c[i] != c[A]) {           // 如果节点i与A颜色不同
            ans = max(ans, d[0][i]);  // 更新答案,取当前最大值
        }
    }
    
    // 情况2:考虑以B为端点的最远异色节点对
    // 遍历所有节点,找到与B颜色不同的节点,更新最大距离
    for (int i = 1; i <= n; i++) {
        if (c[i] != c[B]) {           // 如果节点i与B颜色不同
            ans = max(ans, d[1][i]);  // 更新答案,取当前最大值
        }
    }
    
    // 输出最终答案
    cout << ans << "\n";
    
    return 0;
}

功能分析

算法思路
  1. 核心思想:利用树的直径和 BFS 性质
  2. 关键观察:最远异色点对一定包含从某个点出发能到达的最远异色点
  3. 正确性保证:对于任意节点,其最远点一定是直径端点之一
时间复杂度
  • 三次 BFS:O(n)
  • 两次遍历所有节点:O(n)
  • 总复杂度:O(n),满足 n ≤ 10⁵ 的要求
空间复杂度
  • 邻接表:O(n)
  • 距离数组:O(n)
  • 总空间:O(n)
注意事项
  1. 使用 ios::sync_with_stdio(false)cin.tie(0) 加速输入
  2. BFS 使用队列实现,避免递归栈溢出
  3. 颜色数组下标从 1 开始,符合题目输入
  4. 保证至少有一对异色节点(题目保证)
测试用例验证

对于样例:

复制代码
5
0 1 0 1 0
1 2
1 3
3 4
3 5

树结构:

复制代码
    1
   / \
  2   3
     / \
    4   5

颜色:1(0), 2(1), 3(0), 4(1), 5(0)

最远异色点对:节点 2(黑) 和 节点 5(白)

距离 = 2->1->3->5 = 3

算法输出:3


各种学习资料,助力大家一站式学习和提升!!!

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"##########  一站式掌握信奥赛知识!  ##########";
	cout<<"#############  冲刺信奥赛拿奖!  #############";
	cout<<"######  课程购买后永久学习,不受限制!   ######";
	return 0;
}

1、csp信奥赛高频考点知识详解及案例实践:

CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转

CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转

信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html

2、csp信奥赛冲刺一等奖有效刷题题解:

CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新):https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转

CSP信奥赛C++一等奖通关刷题题单及题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转

3、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html

4、CSP信奥赛C++竞赛拿奖视频课:

https://edu.csdn.net/course/detail/40437 点击跳转

· 文末祝福 ·

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int main(){
	cout<<"跟着王老师一起学习信奥赛C++";
	cout<<"    成就更好的自己!       ";
	cout<<"  csp信奥赛一等奖属于你!   ";
	return 0;
}
相关推荐
端平入洛1 天前
auto有时不auto
c++
哇哈哈20212 天前
信号量和信号
linux·c++
多恩Stone2 天前
【C++入门扫盲1】C++ 与 Python:类型、编译器/解释器与 CPU 的关系
开发语言·c++·人工智能·python·算法·3d·aigc
蜡笔小马2 天前
21.Boost.Geometry disjoint、distance、envelope、equals、expand和for_each算法接口详解
c++·算法·boost
超级大福宝2 天前
N皇后问题:经典回溯算法的一些分析
数据结构·c++·算法·leetcode
weiabc2 天前
printf(“%lf“, ys) 和 cout << ys 输出的浮点数格式存在细微差异
数据结构·c++·算法
问好眼2 天前
《算法竞赛进阶指南》0x01 位运算-3.64位整数乘法
c++·算法·位运算·信息学奥赛
yyjtx2 天前
DHU上机打卡D31
开发语言·c++·算法
czxyvX2 天前
020-C++之unordered容器
数据结构·c++
会编程的土豆2 天前
2.25 做题
数据结构·c++·算法