树形dp compare E

 
题目大意:给你一棵树,让你放最少的东西来覆盖所有的边
 
这个题目之前写过,就是一个简单的树形dp的板题,因为这个每一个节点都需要挺好处理的。
这个树形dp是从底往根部来递推,所以每一个点,都是由它的根节点来递推的。
如果一个根节点的子节点放了东西,那么这个根节点就可以有选择,但是如果没有放东西,那么这个根节点就必须放东西。
 

题目大意:给你一棵树,让你用最小的东西来覆盖所有的点。

这个题目和上面那个很像,但是有点不太一样,如果是覆盖所有的点,就不一点要覆盖所有的边,但是如果覆盖了所有的边就肯定会覆盖所有的点。

那么这个题目应该怎么考虑呢,这个同样是一个树形dp,每一个点都是由它的子节点推过来的。

这个就和上面那个有一点不太一样,但是很像。

上面那个对于每一个根节点,只要有一个子节点没有放东西,那么这个根节点肯定要放东西。

而这个题目就不太一样,对于每一个节点,如果想要被覆盖,那么有三种可能,一个是它本身放了东西,一个是它的父节点放了东西,一个是它的子节点放了东西。

所以这个dp对于每一个节点就可以有三种状态。

dp[cur][0]表示这个点被放了东西

dp[cur][1]表示这个点的子节点被放了东西。

dp[cur][2]表示这个点的父节点被放了东西

状态定义好了,这个转移方程就比较好写了。

dp[cur][0]=min(dp[x][0],dp[x][1],dp[x][2])     如果它被放了东西,那么它的子节点就肯定已经被覆盖了

dp[cur][1]=min(dp[x][0],dp[x][1])    这个为什么没有dp[x][2]因为我们已经确定cur这个节点不会放东西。

dp[cur][2]=min(dp[x][0],dp[x][1])    为什么这个dp[x][2]没有呢,理由同上。

但是这个还有一点点小问题要注意

第一个就是dp[cur][0]=1 因为这个点被放了东西,所以要+1

但是dp[cur][1]不需要给她初值1 因为它是由它的子节点推过来 而子节点已经被赋值过了。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <iostream>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 100;
int dp[maxn][4];
vector<int>G[maxn];

void dfs(int u,int pre)
{
//    printf("www dp[%d][0]=%d dp[%d][1]=%d dp[%d][2]=%d
", u, dp[u][0], u, dp[u][1], u, dp[u][2]);
    bool ok = false;
    int dif = inf;
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if (v == pre) continue;
        dfs(v, u);
    }
    for(int i=0;i<G[u].size();i++)
    {
        int v = G[u][i];
        if (v == pre) continue;
        dp[u][0] += min(min(dp[v][1], dp[v][0]), dp[v][2]);
        dp[u][2] += min(dp[v][1], dp[v][0]);
        dif = min(dif, abs(dp[v][1] - dp[v][0]));
        if(dp[v][0]<dp[v][1])
        {
            ok = true;
            dp[u][1] += dp[v][0];
        }
        else dp[u][1] += dp[v][1];
    }
    if (!ok) dp[u][1] += dif;
    //printf("dp[%d][0]=%d dp[%d][1]=%d dp[%d][2]=%d
", u, dp[u][0], u, dp[u][1], u, dp[u][2]);
}

int main()
{
    int n;
    scanf("%d", &n);
    for(int i=1;i<n;i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    for (int i = 1; i <= n; i++) dp[i][0] = 1;
    dfs(1, -1);
    printf("%d
", min(dp[1][0], dp[1][1]));
    return 0;
}
树形dp
原文地址:https://www.cnblogs.com/EchoZQN/p/11009125.html