• BZOJ 1304: [CQOI2009]叶子的染色


    1304: [CQOI2009]叶子的染色

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 566  Solved: 358
    [Submit][Status][Discuss]

    Description

    给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根、内部结点和叶子均可)着以黑色或白色。你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身)。 对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色。给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少。

    Input

    第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数。结点编号为1,2,…,m,其中编号1,2,… ,n是叶子。以下n行每行一个0或1的整数(0表示黑色,1表示白色),依次为c[1],c[2],…,c[n]。以下m-1行每行两个整数a,b(1<=a < b <= m),表示结点a和b 有边相连。

    Output

    仅一个数,即着色结点数的最小值。

    Sample Input

    5 3
    0
    1
    0
    1 4
    2 5
    4 5
    3 5

    Sample Output

    2

    HINT

    M<=10000


    N<=5021

    Source

    分析:

    好久每写过这么短的代码了233...

    我们假定已经选定了根节点,那么就变成了一道很水的树形DP,f[i][0/1]代表以i为根节点的子树i染成0/1的最少染色节点数,转移就不说了,自己看吧...

    现在我们不知道根节点是什么?换根么?再仔细思考一下...其实可以证明无论选择谁做根结点都是一样的...

    看12这两个节点,首先这两个节点颜色不可能相同,如果相同那么把一个变成透明的一定更优,所以无论12哪个为根节点ans不变...

    如果颜色不同呢,那么貌似更没有影响了...

    所以我们随便选择一个非叶子节点作为根DP一遍就好了...

    代码:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 //by NeighThorn
     6 #define inf 0x3f3f3f3f
     7 using namespace std;
     8 
     9 const int maxn=10000+5;
    10 
    11 int n,m,c[maxn],hd[maxn],to[maxn*2],nxt[maxn*2],cnt,f[maxn][2];
    12 
    13 inline void add(int x,int y){
    14     to[cnt]=y;nxt[cnt]=hd[x];hd[x]=cnt++;
    15 }
    16 
    17 inline void dfs(int root,int fa){
    18     f[root][0]=f[root][1]=1;
    19     if(root<=m){
    20         if(c[root]==0)
    21             f[root][1]=inf;
    22         else
    23             f[root][0]=inf;
    24     }
    25     for(int i=hd[root];i!=-1;i=nxt[i])
    26         if(to[i]!=fa){
    27             dfs(to[i],root);
    28             f[root][0]+=min(f[to[i]][0]-1,f[to[i]][1]);
    29             f[root][1]+=min(f[to[i]][1]-1,f[to[i]][0]);
    30         }
    31 }
    32 
    33 signed main(void){
    34     memset(hd,-1,sizeof(hd));
    35     scanf("%d%d",&n,&m);cnt=0;
    36     for(int i=1;i<=m;i++)
    37         scanf("%d",&c[i]);
    38     for(int i=1,x,y;i<n;i++)
    39         scanf("%d%d",&x,&y),add(x,y),add(y,x);
    40     dfs(m+1,-1);
    41     printf("%d
    ",min(f[m+1][0],f[m+1][1]));
    42     return 0;
    43 }
    View Code

    by NeighThorn

  • 相关阅读:
    position笔记
    IFE-33笔记
    IFE-31 笔记
    selectedIndex
    iFE-30 笔记
    基于select的python聊天室程序
    python select网络编程详细介绍
    (转载)centos yum源的配置和使用
    python 多进程使用总结
    python迭代器实现斐波拉契求值
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6188302.html
Copyright © 2020-2023  润新知