Daimayuan Online Judge #556. 三进制循环

该博客介绍了一种使用树形动态规划解决的问题,即在树结构中找到从根节点开始,使得每个节点值等于其父节点值加1取模3的结果的最长序列。博主详细阐述了状态定义、状态转移方程,并提供了AC代码实现。通过递归的dfs函数,计算每个节点以递增或递减方式向子节点延伸的最长序列,最终得到整个树中最长序列的长度。
摘要由CSDN通过智能技术生成

算法分析

树形dp

题目要求从第二个结点开始,每个节点的值都等于上一个节点的值 + 1 % 3 的结果,希望这个序列最长,那么树上问题,对于一个结点来说,经过他最长的序列肯定就是,向子树中的某一侧走到底的最佳答案 + 向子树中的另外一侧走到底的最佳答案

那么最后的答案就是某一侧长度 + 另外一侧长度 - 1

那么按照这个思路思考下去就可以脑补出状态的定义了。

状态表示

dp[i][0]:i 结点向下搜,满足 子节点为父节点 + 1 % 3 后的结果 的最长长度

(也可以理解为从上往下是递增的

dp[i][1]:i 结点向下搜,满足 父节点为子节点 + 1 % 3 后的结果 的最长长度

(也可以理解为从上往下是递减的

这样子两侧的链合并时才能是一个方向的

状态转移

void dfs(int now,int fa)
{
    dp[now][0] = dp[now][1] = 1;
    for(auto ne : g[now])
    {
        if(ne == fa) continue;
        dfs(ne,now);
        if((a[now] + 1) % 3 == a[ne])//从父节点看子节点 
            dp[now][0] = max(dp[now][0],dp[ne][0] + 1);
        if((a[ne] + 1) % 3 == a[now])//由子节点看父节点
            dp[now][1] = max(dp[now][1],dp[ne][1] + 1);
    }
    ans = max(ans,dp[now][0] + dp[now][1] - 1);
}

AC Code

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
vector<int>g[N];
int a[N],dp[N][2];
int ans = - 1;

void dfs(int now,int fa)
{
    dp[now][0] = dp[now][1] = 1;
    for(auto ne : g[now])
    {
        if(ne == fa) continue;
        dfs(ne,now);
        if((a[now] + 1) % 3 == a[ne])//从父节点看子节点 
            dp[now][0] = max(dp[now][0],dp[ne][0] + 1);
        if((a[ne] + 1) % 3 == a[now])//由子节点看父节点
            dp[now][1] = max(dp[now][1],dp[ne][1] + 1);
    }
    ans = max(ans,dp[now][0] + dp[now][1] - 1);
}
int main()
{
    int n;
    cin >> n;
    for(int i  = 1;i <= n - 1;i ++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    for(int i = 1;i <= n;i ++) scanf("%d",&a[i]);
    dfs(1,0);
    printf("%d",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cold啦啦啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值