Luogu

BZOJ

分析

显然,合法的状态数不会太多。

于是可以状压一下轮廓线 (其实就是记录一下每行填到了哪一列) ,然后写一发对抗搜索。

然后如果用 $\mathrm{map}$ 记状态的话可能会T,于是用 $\mathrm{unordered\_map}$ 就行了。

具体实现及细节见代码。

代码

//It is made by M_sea
#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define re register
typedef long long ll;
using namespace std;

inline int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=10+10;
const int BASE=12;

int n,m;
int a[N][N],b[N][N],h[N];
unordered_map<ll,int> f;

inline ll encode() {
    ll ans=0;
    for (re int i=1;i<=n;++i) ans=ans*BASE+h[i];
    return ans;
}

inline void decode(ll s) {
    for (re int i=n;i;--i) h[i]=s%BASE,s/=BASE;
}

inline int calc() { //根据已经下的棋子的奇偶性,判断谁下这一步
    int s=0;
    for (re int i=1;i<=n;++i) s+=h[i];
    return s&1;
}

inline int dfs(ll sta) {
    if (f.find(sta)!=f.end()) return f[sta]; //记忆化
    decode(sta); int op=calc(),ans=op?1e9:-1e9;
    for (re int i=1;i<=n;++i) {
        if (h[i-1]<=h[i]) continue;
        ++h[i];
        if (op) ans=min(ans,dfs(encode())-b[i][h[i]]);
        else ans=max(ans,dfs(encode())+a[i][h[i]]);
        --h[i];
    }
    return f[sta]=ans;
}

int main() {
    n=read(),m=read(); h[0]=m;
//  这里 h[0]=m 是为了搜索时更方便判断
    for (re int i=1;i<=n;++i)
        for (re int j=1;j<=m;++j)
            a[i][j]=read();
    for (re int i=1;i<=n;++i)
        for (re int j=1;j<=m;++j)
            b[i][j]=read();
    for (re int i=1;i<=n;++i) h[i]=m; f[encode()]=0; //这里处理一下终态
    printf("%d\n",dfs(0));
    return 0;
}
最后修改:2019 年 09 月 25 日 01 : 36 PM