[九省联考2018]一双木棋chess
P4363 [九省联考2018]一双木棋chess
题意:
两人下棋,要求下棋时上面左面必须全有棋子,否则不能下,双方采用得分最优策略,询问两人得分之差。
分析:
棋盘的状态可以用一个倒着的三角形表示(因为下棋限制条件),同时因为数据范围:
可以用到 轮廓线 \(dp\) 。
设竖着的状态是 \(1\) ,横着的状态是 \(0\) 。
根据倒三角形设置初始状态:\(11111(n)000000(m)\) ,结尾状态:\(00000(n)111111(m)\) ,括号里为数字多少。
转移时, 若是要转移第几位,意思就是从 \(10\) 变成 \(01\) ,我们可以看成 \(\&3\)
同时,因为两者希望最优策略,即:
先行者希望取到自己的最大值,后行者希望对方取到最小值,因此状态转移时,先行者取 \(max\) ,后行者取 \(min\) 。
我们枚举每一位,询问能否变化 \(((sta>>i&3)!=1)\) ,也就是向上连接的数是 \(0\) 而不是 \(1\) . 然后根据人物,选择当前状态的 \(min/max\) 即可。
最后输出最终状态即可。
代码:
// P4363 [九省联考2018]一双木棋chess
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=10,inf=1e9+7;
int n,m,a[N][N],b[N][N],dp[1<<20];
int dfs(int now,bool opt,int n,int m){
if(~dp[now]) return dp[now];//记忆化,通过-1判重
dp[now]=opt?-inf:inf;//根据选择的人判断选取ans 最小值/最大值
int x=n,y=0;
for(int i=0;i<n+m-1;i++){//状态转移哪一位
if(now>>i&1) x--; else y++;
if((now>>i&3)!=1) continue;
int nxt=now^(3<<i);//从[10] 变成 [01] ,就是异或3
//minmax容斥
if(opt) dp[now]=max(dp[now],dfs(nxt,opt^1,n,m)+a[x][y]);
else dp[now]=min(dp[now],dfs(nxt,opt^1,n,m)-b[x][y]);
}
return dp[now];
}
signed main(){
cin>>n>>m;
for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%lld",&a[i][j]);
for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%lld",&b[i][j]);
memset(dp,-1,sizeof(dp));
dp[((1<<n)-1)<<m]=0;//一开始状态设为 1111111(n个)000000000(m个)
printf("%lld\n",dfs((1<<n)-1,1,n,m));
system("pause");
return 0;
}
不关注的有难了😠😠😠https://b23.tv/hoXKV9

浙公网安备 33010602011771号