• 【BalticOI2003】Gem 题解(树形DP)


    题目大意:

    给树上每一个结点赋值(值为正整数),要求相邻结点的权值不能相同。问树上最小权值和。$nleq 10000$。

    -------------------------

    设$f[i][j]$表示以$i$为根的子树,根权值为$j$时子树的最小权值和。

    朴素的$DP$是$n^3$的。这里我们有个结论:树上用到的颜色不超过$log_{2} n$个。下面给出证明(orz大佬):

    假设我们找到点$i$为树的重心。根据重心的性质,它的最大子树的结点数不超过$frac{n}{2}$。考虑一种最差的情况:假设每棵子树的重心都要染上新的颜色。递归的次数是$log$次,所以树上用到的颜色不超过$log_{2} n$个。

    这样$j$最大是$14$,总复杂度$(log^{2} n)*n$。

    ----------------------------------

    更新:解释一下01染色法为什么不对。

    假设现在有一棵树,某些结点它有很多很多个子节点(不是子树),为了保证答案的最优性,必须保证这些子节点权值为$1$。现在考虑父节点。假设这些父节点都是相连的,所以这些父节点权值不能相同。如果父节点的个数大于$2$,那么必须引入大于$2$的权值来保证最优解。因此01贪心法是不对的。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int f[10005][21];
    int head[20005],cnt;
    int n,ans=0x3f3f3f3f;
    struct node
    {
        int next,to;
    }edge[20005];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f; 
    }
    void add(int from,int to)
    {
        edge[++cnt].next=head[from];
        edge[cnt].to=to;
        head[from]=cnt;
    }
    void dfs(int now,int fa)
    {
        for (int i=1;i<=20;i++) f[now][i]=i;
        for (int i=head[now];i;i=edge[i].next)
        {
            int to=edge[i].to;
            if (to==fa) continue;
            dfs(to,now);
            for (int j=1;j<=20;j++)
            {
                int minn=0x3f3f3f3f;
                for (int k=1;k<=20;k++)
                {
                    if (j!=k) minn=min(minn,f[to][k]);
                }
                f[now][j]+=minn;
            }
        }
    }
    int main()
    {
        n=read();
        for (int i=1;i<n;i++)
        {
            int x=read(),y=read();
            add(x,y);add(y,x);
        }
        dfs(1,0);
        for (int i=1;i<=20;i++) ans=min(ans,f[1][i]);
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    c#多线程
    [2017.02.05] 阅读《Efficient C++》思维导图
    [2017.02.04] C++学习记录(1)
    [2017.01.04] 经典排序算法思想及其实现
    [2017.01.04] 2017 新年展望
    [151225] Python3 实现最大堆、堆排序,解决TopK问题
    [160111] Python学习记录
    [151116 记录] 使用Python3.5爬取豆瓣电影Top250
    151111 sqlite3数据库学习
    20141127 测试使用Word2013书写博客(代码高亮+公式支持)。
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12905504.html
Copyright © 2020-2023  润新知