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\n",f[1][m]+(bool)(Max[1][m]>0));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/1124828077ccj/p/12427827.html
今日推荐