这道题和网络收费那道题的套路是一样的.
都是直接枚举每一个点的状态.
但是要注意:这里枚举每个点的状态是基于 dfs 的,所以有递归式:$f(T)=4\times f(\frac{T}{2})$ (算两次)
那么就有 $f(ROOT)=4^n$.
这个是仅考虑 dfs 部分的复杂度,要是把背包部分算进去的话就再乘一个 $n$ 就行了.
当枚举到叶子节点的时候直接判一下祖先的选择情况,然后把点权下放给叶子即可.
code:
#include <bits/stdc++.h>
#define N 1030
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,w[N][12],v[N][12],f[N][N],p[12];
void dfs(int x,int d)
{
int i,j;
for(i=0;i<=(1<<d);++i)
f[x][i]=0;
if(!d)
{
for(i=1;i<=n;++i)
{
if(p[i])
f[x][1]+=w[x][i];
else
f[x][0]+=v[x][i];
}
return;
}
p[d]=0,dfs(x<<1,d-1),dfs(x<<1|1,d-1);
for(i=0;i<=1<<(d-1);++i)
for(j=0;j<=1<<(d-1);++j)
f[x][i+j]=max(f[x][i+j],f[x<<1][i]+f[x<<1|1][j]);
p[d]=1,dfs(x<<1,d-1),dfs(x<<1|1,d-1);
for(i=0;i<=1<<(d-1);++i)
for(j=0;j<=1<<(d-1);++j)
f[x][i+j]=max(f[x][i+j],f[x<<1][i]+f[x<<1|1][j]);
}
int main()
{
// setIO("input");
int i,j,m,ans=0;
scanf("%d%d",&n,&m),--n;
for(i=0;i<(1<<n);++i)
for(j=1;j<=n;++j)
scanf("%d",&w[i+(1<<n)][j]);
for(i=0;i<(1<<n);++i)
for(j=1;j<=n;++j)
scanf("%d",&v[i+(1<<n)][j]);
dfs(1,n);
for(i=0;i<=m;++i)
ans=max(ans,f[1][i]);
printf("%d\n",ans);
}