试题描述
|
给一棵有 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 |
看注释
#include<iostream> #include<algorithm> #include<cstring> #include<string> #include<cstdio> #include<cstdlib> #include<cmath> using namespace std; inline int rd() { int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } inline void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return ; } int head[100006],to[100006],nxt[100006]; int total=0; int m,n; void add(int x,int y) { total++; to[total]=y; nxt[total]=head[x]; head[x]=total; return ; } int book[100006]; int f[100006][3]; void dfs(int x,int la) { f[x][1]=f[x][0]=1;//注意:0不是无色 if(book[x]!=-1) f[x][!book[x]]=2147483646;//如果一个点已经染色,那么就不可能染成别的颜色 for(int e=head[x];e;e=nxt[e]) { int h=to[e]; if(h!=la) { dfs(h,x); f[x][1]+=min(f[h][0],f[h][1]-1);//如果已经染了一个颜色,子树就不用染同一个颜色,所以可以-1 f[x][0]+=min(f[h][1],f[h][0]-1); } } return ; } int main() { //还是树形DP裸题,看不出来还是不要写了 memset(book,-1,sizeof(book)); m=rd(); n=rd(); for(int i=1;i<=n;i++) book[i]=rd();//读入每个染色节点的颜色 for(int i=1;i<m;i++) { int x,y; x=rd(); y=rd(); add(x,y); add(y,x);//双向存边 } dfs(n+1,0);//直接从n+1开始,之前还傻傻的跑了一个root printf("%d",min(f[n+1][0],f[n+1][1])); return 0; }
最后喜欢的话不如来推荐,评论,关注三连。
不喜欢的话也昧着良心推荐一下吧!!!!