首页 > 代码库 > CodeForces 735E(树形DP)

CodeForces 735E(树形DP)

CodeForces 735E Ostap and Tree

题意:给一棵树,需要给树上的一些节点上色,要求任意节点在距离为k的范围以内至少有一个被染色的点,求方案数。

思路:之前看别人代码,感觉好短,题解也好简略,感觉不是很明朗,现在终于感觉自己看懂一点了,来留一发。

   用 dp[x][i] 记录离节点 x 最近的一个被染色的点距 x 的距离为 i ,对于其子树 dp[y][j] ,如果 i+j<=2*k,则此时 min(i,j)<=k,即在此时是成立的,因此把值存入最近的染色点f[min(i,j)];否则min(i,j)>k无法满足,将无法满足的点同样存入f[max(i,j)]中。每处理完一次子树则用 f 数组 对 dp[x] 数组进行赋值。处理子树过程中,第一次实质上时dp[u][i+1] = dp[v][i],后续的操作相当于已记录的子树 和 未记录的子树相互之间的关系,相互独立,因而满足两个基本的组合原理。最终结果为∑dp[1][i]  (i<=k)。

技术分享
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define mod 1000000007
using namespace std;
vector<int> g[105];
int dp[105][55];
int f[55];
int n,k;
void dfs(int u,int fa){
    dp[u][0]=1;
    dp[u][k+1]=1;
    for(int i=0;i<g[u].size();i++){
        int v=g[u][i];
        if(v==fa) continue;
        dfs(v,u);
        memset(f,0,sizeof(f));
        //对第一颗子树操作相当于 赋值 dp[u][i+1] = dp[v][i];

        //后续的操作相当于已记录的子树 和 未记录的子树相互之间的关系,其分别的两个黑点距离为 j + p + 1;
        //并且改关系满足乘法原理,最终的结果记录时,如果 j + p <= 2 * k 则能够满足,则取最近的黑点,否则取最远的黑点并赋值。
        for(int j=0;j<=2*k;j++)
        for(int p=0;p<=2*k;p++){
            if(j+p<=2*k){
                //min(p+1,j)<=k
                f[min(p+1,j)]+=(1LL*dp[u][j]*dp[v][p])%mod;
                f[min(p+1,j)]%=mod;
            }
            else{
                //max(p+1,j)>k
                f[max(p+1,j)]+=(1LL*dp[u][j]*dp[v][p])%mod;
                f[max(p+1,j)]%=mod;
            }
        }
        for(int j=0;j<=2*k;j++)
            dp[u][j]=f[j];
    }
}
int main(){
    cin>>n>>k;
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    dfs(1,1);
    int ans=0;
    for(int i=0;i<=k;i++){
        ans=(ans+dp[1][i])%mod;
    }
    cout<<ans<<endl;

    return 0;
}
Psong

 

CodeForces 735E(树形DP)