您的位置:首页 > 其它

【JLOI2015】战争调度(war)

2016-07-04 10:02 417 查看

Description



Solution

一开始看这题,毫无头绪……

不过发现n十分的小,最多只有10,想一想暴搜加优化。

先试着打了打暴搜,从上往下枚举状态,然后搜索到子节点的时候,再统计答案,每个父节点的答案是两个子节点答案的和,dfs(x,y,z)表示当前搜到的点二进制状态为x,从根节点到底层打仗的状态为y,然后此时要打仗的人有z个。

然后这样十分的慢……

启发式搜索

看起来名字很高级,其实就是状态标记。用f[x][y][z]来标记当前的状态,假如已经搜索过就直接返回答案。

但是空间会爆怎么办。

有一个很犀利的东西,c++三元数组合并为二元

用这种方法就可以过了。

其他优化

这些很多啦,比如说当前这棵子树的大小小于z就跳过……

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#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];
map<P,int>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]<i||s[x*2+1]<z-i)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<<n)-1)s[i]=1;
fod(i,(1<<n)-1,2)s[i>>1]+=s[i];
fo(i,0,m)ans=max(ans,dfs(1,0,i));
printf("%d\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: