1010. 【CQOI2009】叶子的颜色

洛谷AC通道!

题目让我们求最小染色数量,很容易想到dp。

设 $f_{i, 1/0}$ 表示第i个点染黑、白的最小数量, 初始值均为1(自己一条路)。如果这个点为叶子节点,即已经规定了第一个染色点,那么相反颜色的f因设为inf(不能选择它)。

那么,如何选根?  看下图(转载的hhh),无论我们选择1节点还是2节点,可以发现,只要不是叶子节点,根的变化对答案没有影响。

那么,我们就可以很愉快地得到状态转移方程了:

$f_{u, 0} += min(f_{v,1}, f_{v, 0} - 1)$

$f_{u,1} += min (f_{v,0}, f_{v,1} - 1)$

代码:

#include <bits/stdc++.h>
using namespace std;
#define N 100010
const int inf = (int)1e10;

inline int read(){
    int x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == '-') s = -1;
        c = getchar();     
    } 
    while(isdigit(c)){
        x = x * 10 + (c ^ '0');
        c = getchar();
    } 
    return x * s;
} 

struct node{
    int v, next;
} t[N << 1];
int f[N];
int dp[N][2];

int bian = 0;
inline void add(int u, int v){
    t[++bian] = (node){v, f[u]}, f[u] = bian;
    t[++bian] = (node){u, f[v]}, f[v] = bian;
    return ;
}

int c[N];
int n, m;

void dfs(int now, int fa){
    dp[now][0] = dp[now][1] = 1;
    if(now <= m){
        if(c[now] == 0) dp[now][1] = inf;
        else dp[now][0] = inf;
    }
    for(int i = f[now]; i; i = t[i].next){
        int v = t[i].v;
        if(v != fa){
            dfs(v, now);
            dp[now][0] += min(dp[v][1], dp[v][0] - 1);
            dp[now][1] += min(dp[v][0], dp[v][1] - 1);
        }
    }
    return ;
}

int main(){
    n = read(), m = read();// n 节点总数 m: 叶子 
    for(int i = 1;i <= m; i++)
        c[i] = read();
    for(int i = 1;i < n; i++){
        int x = read(), y = read();
        add(x , y);
    }
    dfs(m + 1, m + 1);
    int ans = min(dp[m+1][0], dp[m+1][1]);
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/wondering-world/p/13356642.html