bzoj千题计划307:bzoj5248: [2018多省省队联测]一双木棋(对抗搜索)

https://www.lydsy.com/JudgeOnline/problem.php?id=5248

 

先手希望先手得分减后手得分最大,后手希望先手得分减后手得分最小

棋盘的局面一定是阶梯状,且从上往下递减

可以将轮廓线作为状态,记忆化搜索

用n个数表示一个状态,第i个数表示第i行放了几个

记忆的状态表示当棋盘为这个状态时,接下来再下的最有解

记忆化搜索节省的是接下来再下的时间

 

#include<map>
 
#include<cstdio>
 
#include<cstring>
 
#include<iostream>
 
#include<algorithm>
 
   
 
#define N 11
 
    
 
using namespace std;
 
   
 
int n,m;
 
   
 
int a[N][N],b[N][N];
 
   
 
struct node
 
{
 
    int v[N];
 
    node()
 
    {
 
        memset(v,0,sizeof(v));
 
    }
 
    bool operator < (node p) const
 
    {
 
        for(int i=1;i<=n;++i)
 
            if(v[i]<p.v[i]) return true;
 
            else if(v[i]>p.v[i]) return false;
 
    }
 
};
 
map<node,int>mp;
 
   
 
int dfs(node now,bool who)
 
{
 
    if(mp.find(now)!=mp.end()) return mp[now];
 
    int i;
 
    for(i=1;i<=n;++i)
 
        if(now.v[i]<m) break;
 
    if(i>n) return 0;
 
    int s;
 
    if(!who) s=-2e9;
 
    else s=2e9;
 
    for( i=1;i<=n;++i)
 
         if(now.v[i]!=m && (now.v[i]<now.v[i-1] || i==1))
 
         {
 
             now.v[i]++;
 
             if(!who) s=max(s,dfs(now,who^1)+a[i][now.v[i]]);
 
             else s=min(s,dfs(now,who^1)-b[i][now.v[i]]);
 
             now.v[i]--;
 
        }
 
    return mp[now]=s;
 
}
 
   
 
int main()
 
{
 
 //  freopen("data.in","r",stdin);
 
    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]);
 
    node now;
 
    printf("%d",dfs(now,0));
 
}

 

posted @ 2018-04-25 20:04  TRTTG  阅读(401)  评论(0编辑  收藏  举报