• [BZOJ 1369][树形DP] Gem


    树形DP题

    这题乍一看会觉得:“这啥玩意,染遍色不就出来了吗,这么水?”

    然后就会发现直接WA掉

    其实这题是个树形DP题,我们可以发现当类似“偶数个节点链接了两颗大子树”之类强制让你的结构中一大部分点使用 2 作为点权的情况时,仅用两个颜色并不能得到最优解。

    而且这题的恶心之处在于它还是个结论题:可以证明按题意染色一棵树需要的颜色种数不超过log(n)

    显然我是不会证的,但有神仙证出来了(而且机房You神也证出来了貌似%%%)


    于是可以写树形DP:f[i][j] 表示 以 i 节点为根节点的一棵子树,当 i 节点的颜色(点权)为 j 时可得的最小点权和

    而转移就很显然了:

      f[i][j] = ∑(min(f[k][l])) 其中 k 是 i 的子节点,l,j∈[1, 15] 且 l ≠ j

    代码如下:

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # define MAXN 10005
     5 # define MAXINT 2<<20
     6 
     7 using namespace std;
     8 
     9 struct edge{
    10     int u, v;
    11     int next;
    12 }e[MAXN <<2];
    13 
    14 int head[MAXN], cntEdge, f[MAXN][21];
    15 
    16 void addEdge(int u, int v){
    17     e[cntEdge++].u = u;
    18     e[cntEdge].v = v;
    19     e[cntEdge].next = head[u];
    20     head[u] = cntEdge;
    21     return;
    22 }
    23 
    24 void dfs(int now, int fa){
    25     for(int i = head[now]; i; i = e[i].next)
    26         if(e[i].v != fa)
    27             dfs(e[i].v, now);
    28 
    29     for(int i = 1; i <= 20; i++)
    30         for(int j = head[now]; j; j = e[j].next)
    31             if(e[j].v != fa){
    32                 int ans = MAXINT;
    33                 for(int k = 1; k <= 20; k++)
    34                     if(i != k)
    35                         ans = min(ans, f[e[j].v][k]);
    36                 f[now][i] += ans;
    37             }
    38     return;
    39 }
    40 
    41 int main(){
    42     int n, x, y, ans = MAXINT; 
    43     scanf("%d", &n);
    44     
    45     for(int i = 1; i <= n; i++)
    46         for(int j = 1; j <= 20; j++)
    47             f[i][j] = j; // 初始化
    48     
    49 
    50     for(int i = 1; i < n; i++){
    51         scanf("%d%d", &x, &y);
    52         addEdge(x, y);
    53         addEdge(y, x);
    54     }
    55 
    56     dfs(1, 0);
    57 
    58     for(int i = 1; i <= 20; i++)
    59         ans = min(ans, f[1][i]);
    60 
    61     printf("%d", ans);
    62 
    63     return 0;
    64 }

    复杂度大概是 O(log(n^2)) 的吧。。 这东西我根本不会算

    以上

  • 相关阅读:
    Intent.ACTION_TIME_TICK 广播
    Android ContentObserver
    android:duplicateParentState属性解释
    Android CursorAdapter
    android AndroidManifest.xml 多个android.intent.action.MAIN (
    PreferenceActivity详解
    WORD和WPS中英文混合的内容间距离很大怎么办?
    Android 屏幕适配
    OC第四课
    PL/SQL联系oracle成功可以sql解决的办法是检查表的名称无法显示
  • 原文地址:https://www.cnblogs.com/Foggy-Forest/p/12902451.html
Copyright © 2020-2023  润新知