【题解】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;
}
posted @ 2025-12-18 08:30  Ming3398  阅读(15)  评论(0)    收藏  举报