【JLOI2015】战争调度(war)

Description

【JLOI2015】战争调度(war)_第1张图片

Solution

一开始看这题,毫无头绪……
不过发现n十分的小,最多只有10,想一想暴搜加优化。
先试着打了打暴搜,从上往下枚举状态,然后搜索到子节点的时候,再统计答案,每个父节点的答案是两个子节点答案的和,dfs(x,y,z)表示当前搜到的点二进制状态为x,从根节点到底层打仗的状态为y,然后此时要打仗的人有z个。
然后这样十分的慢……

启发式搜索

看起来名字很高级,其实就是状态标记。用f[x][y][z]来标记当前的状态,假如已经搜索过就直接返回答案。
但是空间会爆怎么办。
有一个很犀利的东西,c++三元数组合并为二元。
用这种方法就可以过了。

其他优化

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

Code

#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);
}

你可能感兴趣的:(省选,暴搜,启发式搜索)