LOJ #2111. 「JLOI2015」战争调度 树形DP+复杂度分析
这道题和网络收费那道题的套路是一样的.
都是直接枚举每一个点的状态.
但是要注意:这里枚举每个点的状态是基于 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); }