码迷,mamicode.com
首页 > 其他好文 > 详细

【BalticOI2003】Gem 题解(树形DP)

时间:2020-05-17 16:05:21      阅读:65      评论:0      收藏:0      [点我收藏+]

标签:std   read   sdi   struct   要求   col   lin   alt   add   

题目大意:

给树上每一个结点赋值,要求相邻结点的权值不能相同。问树上最小权值和。$n\leq 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$。

代码:

#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;
}

 

【BalticOI2003】Gem 题解(树形DP)

标签:std   read   sdi   struct   要求   col   lin   alt   add   

原文地址:https://www.cnblogs.com/Invictus-Ocean/p/12905504.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!