一开始看这题,毫无头绪……
不过发现n十分的小,最多只有10,想一想暴搜加优化。
先试着打了打暴搜,从上往下枚举状态,然后搜索到子节点的时候,再统计答案,每个父节点的答案是两个子节点答案的和,dfs(x,y,z)表示当前搜到的点二进制状态为x,从根节点到底层打仗的状态为y,然后此时要打仗的人有z个。
然后这样十分的慢……
看起来名字很高级,其实就是状态标记。用f[x][y][z]来标记当前的状态,假如已经搜索过就直接返回答案。
但是空间会爆怎么办。
有一个很犀利的东西,c++三元数组合并为二元。
用这种方法就可以过了。
这些很多啦,比如说当前这棵子树的大小小于z就跳过……
#include
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef pair<int,int>P;
const int maxn=1207;
int i,j,k,l,t,n,m,ans;
int a[maxn*2][maxn],b[maxn*2][maxn];
int d[maxn],s[maxn*2];
mapint
>h[maxn];
int dfs(int x,int y,int z){
int i,&j=h[x][P(y,z)];
if(j)return j;
j=0;
if(x>=(1<<(n-1))){
fo(i,1,n-1){
if(z&&(y&(1<<(i-1))))j+=a[x-(1<<(n-1))+1][i];
else if(!z&&!(y&(1<<(i-1))))j+=b[x-(1<<(n-1))+1][i];
}
return j;
}
fo(i,0,z){
if(s[x*2]2+1]continue;
j=max(j,dfs(x*2,y<<1,i)+dfs(x*2+1,y<<1,z-i));
j=max(j,dfs(x*2,(y<<1)+1,i)+dfs(x*2+1,(y<<1)+1,z-i));
}
return j;
}
int main(){
freopen("war.in","r",stdin);
freopen("war.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,1<<(n-1))fo(j,1,n-1)scanf("%d",&a[i][j]);
fo(i,1,1<<(n-1))fo(j,1,n-1)scanf("%d",&b[i][j]);
fo(i,1<<(n-1),(1<1)s[i]=1;
fod(i,(1<1,2)s[i>>1]+=s[i];
fo(i,0,m)ans=max(ans,dfs(1,0,i));
printf("%d\n",ans);
}