zoukankan      html  css  js  c++  java
  • 树的最大独立集

    题意: 对于一棵有N个结点的无根树,选出尽量多的结点,使得任何两个结点均不相邻(称为最大独立集)。

    Sol:树形dp

    由于每个点只由其儿子或者孙子决定(二者的最大值),所以我们可以深搜一遍,回溯的时候用当前节点更新其父亲以及父亲的父亲(因为此时该节点的值已经被我们计算出来了),这种由已知贡献给未知的方法称为刷表法。

    刷表法的唯一限制是,对于一个状态(记为S)所依赖的所有状态(记为S')而言,这些状态对当前状态的贡献必须是独立的。(即S'是互相独立的)

    如此可以写出DP。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 105, maxm = maxn * 2;
    
    int n, tot;
    
    int fa[maxn][25], s[maxn], gs[maxn], h[maxn], d[maxn];
    
    struct edge
    {
        int v, next;
    }a[maxm];
    
    void add(int x, int y)
    {
        a[tot].v = y;
        a[tot].next = h[x];
        h[x] = tot++;
    }
    
    void dfs(int u, int fat)
    {
        for (int i = 1; i <= 20; i++) fa[u][i] = fa[fa[u][i -1]][i - 1];
        for (int i = h[u]; ~i; i = a[i].next)
        {
            int v = a[i].v;
            if (v == fat) continue;
            fa[v][0] = u;
            dfs(v, u);
        }
        d[u] = max(s[u], gs[u] + 1);//此时d[u]的值已经被计算出来了。
        s[fa[u][0]] += d[u];//贡献给父亲
        gs[fa[u][1]] += d[u];//贡献给父亲的父亲
    }
    
    int main()
    {
        freopen("最大独立集.in","r",stdin);
        scanf("%d", &n);
        tot = 0; memset(h, -1, sizeof h);
        for (int i = 1; i < n; i++)
        {
            int x, y;
            scanf("%d%d", &x, &y);
            add(x, y);
            add(y, x);
        }
        dfs(1, 0);
        printf("%d", d[1]);
        return 0;
    }

    另外,uva1220还要求给出当前最优解是否唯一,这个貌似也要用dp做,之后补坑。

  • 相关阅读:
    [转]被玩坏的innerHTML、innerText、textContent和value属性
    在github上优雅的搭建个人博客
    使用jmeter进行压力测试入门讲解
    一、docker 入坑(win10和Ubuntu 安装)
    使用C#开发Android应用之WebApp
    Win10上的Docker应用:Kubernetes(容器集群)
    Win10上的Docker应用:Docker-compose(容器编排)
    Win10上的Docker应用:Hello World
    在web端使用html5访问远程桌面
    HtmlAgilityPack
  • 原文地址:https://www.cnblogs.com/yohanlong/p/7728214.html
Copyright © 2011-2022 走看看