【题解】P4363 [九省联考 2018] 一双木棋 chess
【P4363】题解
一:【题意】
- 有一张网格图,每个格点有点权a,b
- Alice和Bob在玩一个游戏(Alice先手)
- 每次可以下一步棋,落子的规则是当上边和左边全部下满棋时,才可以在当前位置落子
- Alice可以获得当前落子位置a的贡献,同理Bob可以得到b的贡献
- 双方都采取最优策略,求最后Alick-Bob的得分
二:【解法】
由落子规则知,落子一定填了左上的一部分且构成凸多边形
如果我们把它转化成(n,0)->(0,n)的路径问题,则一定只能向上和向右走,即右下角的轮廓长度恒为n+m
我们可以用0表示向右,1表示向上,此时我们可以用二进制数表示轮廓线
并且容易发现,每个二进制状态只对应一个人,即Min/Max属性不变
dp[S]:表示在当前轮廓的状态下,到游戏结束得分是多少
考虑转移,可以发现,每放一个棋子,就会有一组10->01
如果刷表转移的话很麻烦,所以我们采取记忆化搜索
答案即为dp[0000...1111]
三:【时间复杂度】
n+m中选择n个1,总状态数为C(n+m,n)
所以复杂度为O(C(n+m,n))
四:【代码】
#include<bits/stdc++.h>
#define inf 2e9
#define beg 998244353
using namespace std;
const int N=11;int n,m;
int A[N][N],B[N][N];
int dp[1<<(2*N)];
int Dp(int S,int op){
if(dp[S]!=beg) return dp[S];
if(op==0) dp[S]=-inf;
else dp[S]=inf;
int x=n+1,y=1;
for(int i=0;i<n+m-1;i++){
if(S>>i&1) x--;else y++;
if((S>>i&3)!=1) continue;
int T=S^(3<<i);
Dp(T,!op);
if(op==0) dp[S]=max(dp[S],dp[T]+A[x][y]);
else dp[S]=min(dp[S],dp[T]-B[x][y]);
//cout<<op<<" "<<S<<" "<<T<<" "<<x<<" "<<y<<" "<<dp[S]<<"\n";
}
return dp[S];
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>A[i][j];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin>>B[i][j];
for(int i=0;i<(1<<2*N);i++) dp[i]=beg;
dp[((1<<n)-1)<<m]=0;
cout<<Dp((1<<n)-1,0)<<"\n";
return 0;
}

浙公网安备 33010602011771号