一本通1583叶子的染色
1583:叶子的染色
时间限制: 1000 ms 内存限制: 524288 KB
题目描述
原题来自:CQOI 2009
给一棵有 m 个节点的无根树,你可以选择一个度数大于 1 的节点作为根,然后给一些节点(根、内部节点、叶子均可)着以黑色或白色。你的着色方案应保证根节点到各叶子节点的简单路径上都包含一个有色节点,哪怕是叶子本身。
对于每个叶子节点 u,定义 cu 为从根节点到 u 的简单路径上最后一个有色节点的颜色。给出每个 cu 的值,设计着色方案使得着色节点的个数尽量少。
输入格式
第一行包括两个数 m,n,依次表示节点总数和叶子个数,节点编号依次为 1 至 m。
接下来 n 行每行一个 0 或 1 的数,其中 0 表示黑色,1 表示白色,依次为 c1,c2,⋯,cn 的值。
接下来 m−1 行每行两个整数 a,b,表示节点 a 与 b 有边相连。
输出格式
输出仅一个数,表示着色节点数的最小值。
样例
样例输入
5 3
0
1
0
1 4
2 5
4 5
3 5
样例输出
2
数据范围与提示
数据 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|
m |
10 | 50 | 100 | 200 | 400 | 1000 | 4000 | 8000 | 10000 | 10000 |
n |
5 |
23 | 50 | 98 | 197 | 498 | 2044 | 4004 | 5021 | 4996 |
sol:看上去好复杂的样子,dp[x][0,1]表示在x的子树中x选择颜色0,1时的最小代价,因为在这个子树中根节点放个颜色一定是最优的(不放心的话可以写一下dp[x][2]表示x没有颜色时子树的最小代价),然后暴力转移下去,遇到叶子就弹出
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; inline int read() { int s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(long long x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } inline void writeln(long long x) { write(x); putchar('\n'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) writeln(x) const int N=10005,B=5025,M=20005,inf=0x3f3f3f3f; int n,m,Cor[B]; struct Tree { int tot,Next[M],to[M],head[N]; inline void add(int x,int y) { Next[++tot]=head[x]; to[tot]=y; head[x]=tot; return; } long long dp[N][2]; inline void dfs(int x,int fa) { dp[x][0]=dp[x][1]=1; if(x<=m) { dp[x][Cor[x]^1]=inf; return; } int i; for(i=head[x];i;i=Next[i]) if(to[i]!=fa) { dfs(to[i],x); dp[x][0]+=min(dp[to[i]][0]-1,dp[to[i]][1]); dp[x][1]+=min(dp[to[i]][1]-1,dp[to[i]][0]); } return; } inline void Solve() { dfs(n,0); Wl(min(dp[n][0],dp[n][1])); return; } inline void Init() { tot=0; memset(head,0,sizeof head); return; } }T; int main() { // freopen("9.in","r",stdin); int i; T.Init(); R(n); R(m); for(i=1;i<=m;i++) R(Cor[i]); for(i=1;i<n;i++) { int x=read(),y=read(); T.add(x,y); T.add(y,x); } T.Solve(); return 0; } /* input 5 3 0 1 0 1 4 2 5 4 5 3 5 output 2 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!