题目描述:
有一个 n∗m的方格, Alice 和 Bob 玩游戏。每次每人可以选择一个格子占领,前提是这个格子未被占领且它左上方的所有格子都已被占领。
第 i行第 j 列的格子若被 Alice 占领则 Alice 获得 Ai,j 分,若被 Bob 占领则 Bob 获得 Bi,j分。
Alice 先手,所有格子都被占领时结束。双方都想最大化自己的得分与对方得分的差。求双方采取最优策略时 Alice 得分与 Bob 得分的差。
n,m≤10。
题目分析:
这玩意好像叫做对抗搜索.
因为A想最大化suma-sumb而B想要最小化suma-sumb
考场上就打了个50的暴力…
纯纯的搜索,枚举放的位置,按照当前的人选决策.
考虑到每行放的棋子数量肯定是递减的
即
……..
……
….
..
这样的形式,而且肯定是从左向右的
如果我们用一个m+1进制n位的数来储存每行放旗子的状态,那么我们就可以利用记忆化搜索来优化这个搜索.
所有的状态数
Cmn+m
C
n
+
m
m
2e5左右,那么我们搞个map存结果就好了.
题目链接:
50 Tle 代码:
#include <cstdio>
#include <algorithm>
#include <cstring>
bool vis[12][12];
int a[12][12],b[12][12];
int col[12][12];
int n,m;
struct node{
int ans1,ans2;
};
node dfs(int num,int f)
{
if(num==n*m)
{
int ans1=0,ans2=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(col[i][j]==1) ans1+=a[i][j];
if(col[i][j]==2) ans2+=b[i][j];
}
return (node){ans1,ans2};
}
node ans;
int maxi=-1e9+7;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(vis[i-1][j]||(i-1==0))
if(vis[i][j-1]||(j-1==0))
if(!vis[i][j])
{
vis[i][j]=1;
col[i][j]=f;
node dx=dfs(num+1,f==1?2:1);
vis[i][j]=0;
col[i][j]=0;
int ansx=f==1?dx.ans1-dx.ans2:dx.ans2-dx.ans1;
if(ansx>maxi) maxi=ansx,ans=dx;
}
}
return 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]);
node ans=dfs(0,1);
printf("%d\n",ans.ans1-ans.ans2);
return 0;
}
Ac 代码:
#include <cstdio>
#include <algorithm>
#include <map>
#define ll long long
#define inf 0x7fffffff
std::map <ll,int> mp;
ll end;
int n,m;
int num[20],a[20][20],b[20][20];
inline int unzip(ll sta)
{
int s=0;
for(int i=n;i;i--) s+=(num[i]=(sta%(m+1))),sta/=(m+1);
return s&1;
}
inline ll zip()
{
ll s=0;
for(int i=1;i<=n;i++) s=s*(m+1)+num[i];
return s;
}
int DFS(ll sta)
{
if(mp.find(sta)!=mp.end()) return mp[sta];
if(sta==end) return 0;
int opt=unzip(sta);
int ans=opt?inf:-inf;
if(num[1]<m)
{
++num[1];
if(opt) ans=std::min(ans,DFS(zip())-b[1][num[1]]);
else ans=std::max(ans,DFS(zip())+a[1][num[1]]);
--num[1];
}
for(int i=2;i<=n;i++)
if(num[i-1]>num[i])
{
++num[i];
if(opt) ans=std::min(ans,DFS(zip())-b[i][num[i]]);
else ans=std::max(ans,DFS(zip())+a[i][num[i]]);
--num[i];
}
return mp[sta]=ans;
}
int main()
{
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]);
for(int i=1;i<=n;i++) num[i]=m;
end=zip();
DFS(0);
printf("%d\n",mp[0]);
return 0;
}