zoukankan      html  css  js  c++  java
  • CF1280D Miss Punyverse

    题意:

         

          $n,m<=3000$

    题解:

         由于 $n,m$ 数据范围不大,所以想到 $O(nm)$ 的$dp$。令 $f[i][j]$ 表示以第 $i$ 个点为根,目前划分了 $j$ 个连通块的最优方案的答案。然后考虑转移,发现没法转移,因为我们不知道根的连通块数值大小。

         怎么办?总不能再记一维吧,当然不用,我们只需要考虑在答案最优的情况下,根节点所在的连通块的数值和最大的情况即可。因为如果答案不优,那么根节点无论多大,最多也就多 $1$ 的贡献,所以选取答案最优的贪心是对的,在此情况下再使根节点所在的连通块数值和最大。

         重新定义一下 $dp$ 状态。令 $f[i][j]$ 表示以第 $i$ 个点为根,目前划分了 $j$ 个连通块的最优方案的答案。注意,$j$ 个连通块包括根,但是最优方案的答案不包括根。再记录一个 $Max[i][j]$ 表示在 $f[i][j]$ 尽量大的情况下,根节点所在的连通块的尽可能大的数值。转移的时候,注意分类判断当前子节点是否要合并到根节点上来,根据情况讨论。当然,这种类似树上的背包的问题都少不了一个优化,就是枚举到子节点大小。

    #include<cstdio>
    #include<vector>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const long long INF=1e18;
    int T,n,m,a[3002],s[3002],zjds[3002];
    long long Max[3002][3002],f[3002][3002];
    vector<int>g[3002];
    void dfs(int x,int y){
        zjds[x]=1;
        f[x][1]=0;Max[x][1]=0;
        long long gg[3002],gmax[3002];
        for (int i=0;i<g[x].size();i++)
        if (g[x][i]!=y)
        {
            dfs(g[x][i],x);
            for (int j=1;j<=zjds[x];j++)
            {
                gg[j]=f[x][j];gmax[j]=Max[x][j];
                f[x][j]=-INF;Max[x][j]=-INF;
            }
            for (int j=zjds[x];j>=1;j--)
            {
                for (int k=1;k<=zjds[g[x][i]];k++)
                {
                    if (j+k-1<=m && gg[j]+f[g[x][i]][k]>f[x][j+k-1])
                    {
                        f[x][j+k-1]=gg[j]+f[g[x][i]][k];Max[x][j+k-1]=gmax[j]+Max[g[x][i]][k];
                    }
                    else if (j+k-1<=m && gg[j]+f[g[x][i]][k]==f[x][j+k-1] && gmax[j]+Max[g[x][i]][k]>Max[x][j+k-1])
                    {
                        f[x][j+k-1]=gg[j]+f[g[x][i]][k];Max[x][j+k-1]=gmax[j]+Max[g[x][i]][k];
                    }
                    if (j+k<=m && gg[j]+f[g[x][i]][k]+(bool)(Max[g[x][i]][k]>0)>f[x][j+k])
                    {
                        f[x][j+k]=gg[j]+f[g[x][i]][k]+(bool)(Max[g[x][i]][k]>0);Max[x][j+k]=gmax[j];
                    }
                    else if (j+k<=m && gg[j]+f[g[x][i]][k]+(bool)(Max[g[x][i]][k]>0)==f[x][j+k] && gmax[j]>Max[x][j+k])
                    {
                        f[x][j+k]=gg[j]+f[g[x][i]][k]+(bool)(Max[g[x][i]][k]>0);Max[x][j+k]=gmax[j];
                    }
                }
            }
            zjds[x]+=zjds[g[x][i]];
        }
        for (int i=1;i<=zjds[x];i++)Max[x][i]+=s[x];
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for (int i=1;i<=n;i++)scanf("%d",&a[i]);
            for (int i=1;i<=n;i++)
            {
                scanf("%d",&s[i]);s[i]-=a[i];
            }
            for (int i=1;i<=n;i++)g[i].clear();
            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);
            }
            for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
            {f[i][j]=-INF;Max[i][j]=-INF;}
            dfs(1,0);
            printf("%lld
    ",f[1][m]+(bool)(Max[1][m]>0));
        }
        return 0;
    }
  • 相关阅读:
    python selenium T5
    python selenium T4
    python selenium T3
    python selenium T2
    python selenium T1
    day1——变量,if语句 | day2——while循环
    Python Day48 mysql补充
    Python Day47索引
    Python Day46 MySQL数据备份
    Python Day45多表连接查询
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12427827.html
Copyright © 2011-2022 走看看