zoukankan      html  css  js  c++  java
  • bzoj3090

    树形dp

    有一个比较明显的dp状态是dp[i][j]表示当前i节点的子树已经满足且i剩下j元钱的最小操作次数,这样复杂度比较高状态数已经有O(n*x)的了,转移再来x,肯定不行。

    我们考虑把状态和dp值交换一下,因为操作次数最多只有n-1次,这样可以大大降低dp状态数,于是我们设dp[i][j]表示i的子树已经满足了,且操作了j次,根节点最多能有多少多余的钱,这里可以是负数,我们自然希望子树内满足之后,根节点钱尽量多,这样可以支持其他节点,转移就是背包dp,tmp[i+j+1]=min(tmp[i+j+1],dp[u][i]+dp[v][j]),表示我们把v的钱转移到u上,那么这样又进行了一次操作,如果dp[u][j]>=0,说明u节点满足了,那么我们可以不用子树来支持,那么tmp[i+j]=min(tmp[i+j],dp[u][j]),这样是说不转移,然后那么v上的钱就不可能转移上来了,最后答案就是dp[1][j]>=0的j。

    如果状态过多,有时我们可以考虑交换状态和dp值,这样可以降低复杂度

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    using namespace std;
    const int N = 2010;
    int n, X;
    vector<int> G[N];
    int dp[N][N], tmp[N], v[N], size[N];
    void dfs(int u, int last)
    {   
        size[u] = 1;
    //  for(int i = 0; i <= n; ++i) dp[u][i] = X - v[u];
        dp[u][0] = X - v[u];
        for(int i = 0; i < G[u].size(); ++i)
        {
            int v = G[u][i];
            if(v == last) continue;
            dfs(v, u);
            memset(tmp, -0x3f3f, sizeof(tmp));
            for(int j = 0; j <= size[u]; ++j)
                for(int k = 0; k <= size[v]; ++k)
                {
                    tmp[j + k + 1] = max(tmp[j + k + 1], dp[u][j] + dp[v][k]);
                    if(dp[v][k] >= 0) tmp[j + k] = max(tmp[j + k], dp[u][j]);
                }
            size[u] += size[v];
            for(int j = 0; j <= size[u] + 1; ++j) dp[u][j] = tmp[j];
        }
    }
    int main()
    {
        scanf("%d%d", &n, &X);
        for(int i = 1; i <= n; ++i) scanf("%d", &v[i]);
        for(int i = 1; i < n; ++i)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        memset(dp, -0x3f3f, sizeof(dp));
        dfs(1, 0);
        for(int i = 0; i < n; ++i) if(dp[1][i] >= 0)
        {
            printf("%d
    ", i);
            return 0;
        }
        return 0;
    }
    
    View Code
  • 相关阅读:
    五角星评分小例子
    手风琴案列
    隔行变色
    全选和单选(有一个单选没有打钩,全选也自动不打钩)
    随机数封装
    数组的升降序排列
    js面向对象倒计时与文字左右滚动
    linux知识点总结与随笔(关注linux爱好者公众号的一些笔记)
    线程与进程(我的理解)
    @property在python类中的应用
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7688617.html
Copyright © 2011-2022 走看看