[BZOJ5248][多省联考2018] 一双木棋(对抗搜索+hash)

本文介绍了一种使用对抗搜索解决特定棋盘游戏问题的方法。通过记忆化搜索和状态哈希技术,实现了高效的求解过程。文章详细阐述了如何利用n位m+1进制数来表示游戏状态,并给出了具体的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:

我是超链接

题解:

考试的时候就打了25pts的暴力分
其实从暴力的做法是可以得到启迪的。
我们把所有搜索的状态记录下来,然后如果这一步该A走,就在可以走的几步中选择Max的状态走;如果这一步该B走,就在可以走的几步中选择Min的状态走,这应该是所谓的对抗搜索
考虑一下所有的状态,一定是一个从上往下的阶梯型
因为n,m<=10
所以我们可以用一个n位的m+1进制数把当前下完的轮廓给哈希一下,即第几排选到了第几个。

那么,对于一个局面,我们可以记忆化搜索,
我们只需要根据局面当前下子的是谁,决定这个状态是最大还是最小。这样用map压下当前所有状态,直接搜索即可。。

不要忘记初始化,即最后全选完的时候mmp=0

代码:

#include <map>
#include <cstdio>
#define LL long long
#define INF 1e9
using namespace std;
const LL base=11;
const int N=15;
int h[N],n,m,a[N][N],b[N][N];map<LL,int>mmp;
void unhash(LL st){for (int i=n;i>=1;i--) h[i]=st%base,st/=base;}
int up(){int sb=0;for (int i=1;i<=n;i++) sb+=h[i];return sb&1;}//1 Bob 0 Alice
LL nxt(){LL sb=0;for (int i=1;i<=n;i++) sb=sb*base+(LL)h[i];return sb;}
int dfs(LL st)
{
    if (mmp.count(st)) return mmp[st];
    unhash(st);
    int id=up(),ans;
    if (!id) ans=-INF;else ans=INF;
    for (int i=1;i<=n;i++)
      if (h[i-1]>h[i])
      {
        h[i]++;
        LL now=nxt();
        if (!id) ans=max(ans,dfs(now)+a[i][h[i]]);else ans=min(ans,dfs(now)-b[i][h[i]]);
        h[i]--;
      }
    return mmp[st]=ans;
}
int main()
{
//  freopen("chess.in","r",stdin);
//  freopen("chess.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) 
      for (int j=1;j<=m;j++) scanf("%d",&a[i][j]);
    for (int i=1;i<=n;i++) 
      for (int j=1;j<=m;j++) scanf("%d",&b[i][j]);
    h[0]=m;//第0行相当于是全填满了 
    LL all=0;
    for (int i=1;i<=n;i++) all=all*base+m;
    mmp[all]=0;
    printf("%d",dfs(0));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值