• [CQOI2009]叶子的染色


    首先,选择任意一个度数大于(1)的节点为根的最优的答案都是固定的,具体证明这里不加赘述。

    我们仔细研究,他只要求根节点到叶子节点的最后一个有色节点的颜色。我们对第(x)号节点染色,意味着我们把所有它子树中的叶子节点最近的一个有色节点的颜色就发生了改变。显然,儿子越多的节点性价比越高。

    因此,我们定义(dp_{i,0/1})为第(i)号节点染成第(j)种颜色的最小花费,那么对于(j)号节点是他的儿子,可以把他的儿子染成异色,也可以让儿子的颜色与他一致,有转移方程如下:

    (dp_{i,0}) += (min(dp_{j,0} - 1 , dp_{j,1}))

    (dp_{i,1}) += (min(dp_{j,1} - 1 , dp_{j,0}))

    ```cpp
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int MAXN = 1e4 + 5;
    int head[MAXN] , to[MAXN << 1] , nxt[MAXN << 1] , cnt , n , m;
    int c[MAXN] , dp[MAXN][2];
    void add(int x , int y){nxt[++cnt] = head[x];head[x] = cnt;to[cnt] = y;}
    void read(int &x) {
    	int f = 1;x = 0;char s = getchar();
    	while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
    	while(s >= '0' && s <= '9') {x = (x << 3) + (x << 1) + s - '0';s = getchar();}
    	x *= f;
    }
    void dfs(int x , int fa) {
    	if(x <= n) {
    		dp[x][c[x]] = 1; // 染上的花费
    		dp[x][!c[x]] = 1e9; // 不能染这种颜色,设为无穷大
    		return;
    	}
    	dp[x][0] = dp[x][1] = 1;
    	for (int i = head[x]; i; i = nxt[i]) {
    		if(to[i] == fa) continue;
    		dfs(to[i] , x);
    		dp[x][0] += min(dp[to[i]][0] - 1 , dp[to[i]][1]);
    		dp[x][1] += min(dp[to[i]][0] , dp[to[i]][1] - 1);
    		//转移,如上
        }
    }
    int main() {
    	read(m);read(n);
    	for (int i = 1; i <= n; ++i) read(c[i]);
    	for (int i = 1; i < m; ++i) {
    		int x , y;
    		read(x);read(y);
    		add(x , y);
    		add(y , x);
    	}
    	dfs(m , m);//姑且选m为根节点
    	printf("%d" , min(dp[m][0] , dp[m][1]));
    	return 0;
    }
    
    ```
  • 相关阅读:
    依赖注入(DI)和Ninject
    Dapper.NET——轻量ORM
    优化SQL查询:如何写出高性能SQL语句
    Razor语法
    sublime Text 3 官方版 3114 注册码
    数据库索引,存储过程,视图,事务
    Action向视图传值的6种方式
    C#知识点提要
    算法总结
    c++ 构造函数,拷贝构造函数,析构函数与赋值操作符
  • 原文地址:https://www.cnblogs.com/Reanap/p/13423244.html
Copyright © 2020-2023  润新知