NC13249 黑白树(dp)

Posted ctyakwf

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NC13249 黑白树(dp)相关的知识,希望对你有一定的参考价值。

这道题有着贪心的性质在里面,首先我们观察题目的变量,可以想到设计dp表示以该节点为根节点的子树的最小次数是多少

但是这样是不够的。我们继续观察,发现这道题虽然叶子节点必须染色,但是染色的顺序是不定的,所以我们可以先找到哪种情况是最小的。

因此定义dp[u][1]和dp[u][2]分别表示已被染色的子节点能染色的最长距离和所有子节点传递过来的还能染色的最大距离

因为我们知道,如果dp[u][1]>0说明这个点可以不用加次数,反之就要取dp[u][2]的位置转移,这是最优的。

具体的来说,比如这个树是

                                 1

      2         3

    4     5   6     7

这样的,递归终止肯定是叶子节点,并且这些点必须染色,之后我们来看1这个位置,假如从4,5,6,7涂完色的剩余距离还能染到1,那么自然最小的就是4次,加入不行,说明还至少需要一次的染色

那么我们就可以贪心地找染完之后还剩余距离最大的,比如3的值是5,2的值是3,1的值是3,那么我们肯定选择染3这个位置,那么6 7就可以后染,避免影响到3.虽然从这个树上看不出区别

但是如果上面还有点,那就能看出效果了。

技术图片
#include<iostream>
#include<algorithm>
#include<stack>
#include<vector>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=1e9+7;
int f[N][3];
int k[N];
int h[N],ne[N],e[N],idx;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u){
    if(h[u]==-1){
        f[u][0]=1;
        f[u][1]=k[u];
        f[u][2]=k[u];
        return ;
    }
    f[u][1]=0;
    f[u][2]=k[u];
    for(int i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        dfs(j);
        f[u][0]+=f[j][0];
        f[u][1]=max(f[u][1],f[j][1]-1);
        f[u][2]=max(f[u][2],f[j][2]-1);
    }
    if(f[u][1]<=0){
        f[u][0]++;
        f[u][1]=f[u][2];
    }
}
int main(){
     int i;
     int n;
     cin>>n;
     memset(h,-1,sizeof h);
     for(i=2;i<=n;i++){
        int u,v;
        scanf("%d",&u);
        add(u,i);
     }
     for(i=1;i<=n;i++){
        scanf("%d",&k[i]);
     }
     dfs(1);
     cout<<f[1][0]<<endl;
}
View Code

 

以上是关于NC13249 黑白树(dp)的主要内容,如果未能解决你的问题,请参考以下文章

NC41 最长无重复子数组/NC133链表的奇偶重排/NC116把数字翻译成字符串/NC135 股票交易的最大收益/NC126换钱的最少货币数/NC45实现二叉树先序,中序和后序遍历(递归)(代码片段

深度解析黑白棋AI代码原理(蒙特卡洛搜索树MCTS+Roxanne策略)

深度解析黑白棋AI代码原理(蒙特卡洛搜索树MCTS+Roxanne策略)

深度解析黑白棋AI代码原理(蒙特卡洛搜索树MCTS+Roxanne策略)

cf581F 依赖背包+临时数组 好题

暴力写挂