欢迎光临
我们一直在努力

题解:洛谷 P11251 [GESP202409 八级] 美丽路径

本文分享的必刷题目是从蓝桥云课、洛谷、AcWing等知名刷题平台精心挑选而来,并结合各平台提供的算法标签和难度等级进行了系统分类。题目涵盖了从基础到进阶的多种算法和数据结构,旨在为不同阶段的编程学习者提供一条清晰、平稳的学习提升路径。

欢迎大家订阅我的专栏:算法题解:C++与Python实现!

附上汇总贴:算法竞赛备考冲刺必刷题(C++) | 汇总


【题目来源】

洛谷:P11251 [GESP202409 八级] 美丽路径 – 洛谷

【题目描述】

小杨有一棵包含

n

n

n 个节点的树,节点从

1

1

1 到

n

n

n 编号,并且每个节点要么是白色,要么是黑色。

对于树上的一条简单路径(不经过重复节点的路径),小杨认为它是美丽的当且仅当路径上相邻节点的颜色均不相同。例如下图,其中节点

1

1

1 和节点

4

4

4 是黑色,其余节点是白色,路径

2

−

1

−

3

−

4

2-1-3-4

2−1−3−4 是美丽路径,而路径

2

−

1

−

3

−

5

2-1-3-5

2−1−3−5 不是美丽路径(相邻节点

3

3

3 和

5

5

5 颜色相同)。

对于树上的一条简单路径,小杨认为它的长度是路径包含节点的数量。小杨想知道最长的美丽路径的长度是多少。

【输入】

第一行包含一个正整数

n

n

n,代表节点数量。

第二行包含

n

n

n 个整数

c

1

,

c

2

,

…

,

c

n

c_1,c_2,\\dots,c_n

c1​,c2​,…,cn​,代表每个节点的颜色,如果

c

i

=

0

c_i=0

ci​=0,代表节点

i

i

i 为白色,如果

c

i

=

1

c_i=1

ci​=1,代表节点

i

i

i 为黑色。

之后

n

−

1

n-1

n−1 行,每行包含两个正整数

u

i

,

v

i

u_i,v_i

ui​,vi​,代表存在一条连接节点

u

i

u_i

ui​ 和节点

v

i

v_i

vi​ 的边。

【输出】

输出一个整数,代表最长美丽路径的长度。

【输入样例】

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

【输出样例】

4

【核心思想】

  • 问题分析:给定一棵

    n

    n

    n 个节点的树,每个节点为黑色或白色。求最长"美丽路径"长度——即路径上相邻节点颜色均不相同的简单路径的节点数最大值。本质是一个带颜色约束的树直径问题,需要找到颜色交替的最长链。

  • 算法选择:

    • 树形DP(换根思想的简化版):对每个节点

      u

      u

      u,维护以

      u

      u

      u 为端点的最长和次长"美丽路径"长度,通过子树信息合并计算经过

      u

      u

      u 的最长路径

    • 关键观察:最长美丽路径要么完全在某棵子树内(递归求解),要么经过当前节点

      u

      u

      u 连接两个不同子树的路径(

      f

      1

      [

      u

      ]

      +

      f

      2

      [

      u

      ]

      f1[u] + f2[u]

      f1[u]+f2[u])

  • 关键步骤:

    • 建图与初始化:用邻接表存储树,读取节点颜色

      c

      [

      1..

      n

      ]

      c[1..n]

      c[1..n]

    • DFS树形DP(参数

      u

      u

      u 为当前节点,

      fa

      \\text{fa}

      fa 为父节点):

      • 遍历子节点:对于

        u

        u

        u 的每个邻接节点

        j

        j

        j(跳过父节点

        fa

        \\text{fa}

        fa):

        • 递归计算子树信息:

          DFS

          (

          j

          ,

          u

          )

          \\text{DFS}(j, u)

          DFS(j,u)

        • 颜色判定转移:若

          c

          [

          u

          ]

          ≠

          c

          [

          j

          ]

          c[u] \\neq c[j]

          c[u]=c[j](颜色不同,可延续美丽路径),则

          t

          =

          f

          1

          [

          j

          ]

          +

          1

          t = f1[j] + 1

          t=f1[j]+1;否则

          t

          =

          0

          t = 0

          t=0(路径断裂)

        • 维护最长与次长:将

          t

          t

          t 与

          f

          1

          [

          u

          ]

          f1[u]

          f1[u]、

          f

          2

          [

          u

          ]

          f2[u]

          f2[u] 比较更新,保持

          f

          1

          [

          u

          ]

          ≥

          f

          2

          [

          u

          ]

          f1[u] \\geq f2[u]

          f1[u]≥f2[u]

      • 更新全局答案:

        ans

        =

        max

        ⁡

        (

        ans

        ,

        f

        1

        [

        u

        ]

        +

        f

        2

        [

        u

        ]

        )

        \\text{ans} = \\max(\\text{ans}, f1[u] + f2[u])

        ans=max(ans,f1[u]+f2[u]),表示经过

        u

        u

        u 的最长美丽路径(由两条子链拼接而成)

    • 结果转换:树形DP中

      f

      1

      ,

      f

      2

      f1, f2

      f1,f2 记录的是边数,最终答案为

      ans

      +

      1

      \\text{ans} + 1

      ans+1(转换为节点数)

  • 时间/空间复杂度:

    • 时间复杂度:

      O

      (

      n

      )

      O(n)

      O(n),每个节点只访问一次,每条边只处理一次

    • 空间复杂度:

      O

      (

      n

      )

      O(n)

      O(n),邻接表和DP数组空间

  • 树形DP求带约束直径的核心思想:

    • 子树信息上传:

      f

      1

      [

      u

      ]

      f1[u]

      f1[u] 表示以

      u

      u

      u 为端点、向下延伸的最长美丽路径的边数,通过子节点的

      f

      1

      [

      j

      ]

      f1[j]

      f1[j] 转移得到

    • 颜色断点处理:当

      c

      [

      u

      ]

      =

      c

      [

      j

      ]

      c[u] = c[j]

      c[u]=c[j] 时,路径无法延续,强制

      t

      =

      0

      t = 0

      t=0,确保美丽路径的相邻节点颜色交替

    • 直径拼接原理:经过

      u

      u

      u 的最长路径由

      u

      u

      u 的两个不同子树中的最长链拼接而成,因此维护最长和次长两个值

    • 边数转节点数:DP过程中以边数计算,最终答案加

      1

      1

      1 转换为路径包含的节点数量

    • 适用于树上带约束的最长链、直径变形、颜色/权值限制的路径问题
  • 【算法标签】

    #普及 #树形DP

    【代码详解】

    #include <bits/stdc++.h>
    using namespace std;

    const int N = 100005, M = N * 2;

    int n; // 节点数量
    int c[N]; // c[i] 表示节点i的颜色
    int f1[N]; // f1[i]: 以节点i为起点的最长同色路径长度
    int f2[N]; // f2[i]: 以节点i为起点的次长同色路径长度
    int ans; // 最终答案(路径上的节点数-1,即最大长度)
    int h[N], e[M], ne[M], idx; // 邻接表存储树

    // 添加无向边
    void add(int a, int b)
    {
    e[idx] = b;
    ne[idx] = h[a];
    h[a] = idx++;
    }

    // 深度优先搜索
    // u: 当前节点
    // fa: 父节点
    void dfs(int u, int fa)
    {
    // 遍历所有邻接节点
    for (int i = h[u]; i != –1; i = ne[i])
    {
    int j = e[i]; // 邻接节点
    if (j == fa) // 跳过父节点
    {
    continue;
    }

    // 递归处理子树
    dfs(j, u);

    // 计算从当前节点u到子节点j的路径长度
    // 如果u和j颜色不同,路径长度为f1[j]+1,否则为0
    int t = (c[u] != c[j] ? f1[j] + 1 : 0);

    // 更新f1[u]和f2[u]
    if (t > f1[u])
    {
    f2[u] = f1[u]; // 原来的最大值变为次大值
    f1[u] = t; // 更新最大值
    }
    else if (t > f2[u])
    {
    f2[u] = t; // 更新次大值
    }
    }

    // 更新答案:考虑经过节点u的最长同色路径
    // 注意:这里计算的是路径上的边数,而不是节点数
    ans = max(ans, f1[u] + f2[u]);
    }

    int main()
    {
    cin >> n;

    // 初始化邻接表
    memset(h, –1, sizeof(h));
    idx = 0;

    // 读取每个节点的颜色
    for (int i = 1; i <= n; i++)
    {
    cin >> c[i];
    }

    // 读取树的边
    for (int i = 1; i < n; i++)
    {
    int u, v;
    cin >> u >> v;
    add(u, v);
    add(v, u);
    }

    // 从节点1开始DFS
    dfs(1, 0);

    // 输出结果:最长同色路径的节点数 = 边数 + 1
    cout << ans + 1 << endl;

    return 0;
    }

    【运行结果】

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

    赞(0)
    未经允许不得转载:171主机测评 » 题解:洛谷 P11251 [GESP202409 八级] 美丽路径
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址