Acwing 219. 剪纸游戏
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Acwing 219. 剪纸游戏相关的知识,希望对你有一定的参考价值。
题意:
给定一张 N×M 的矩形网格纸,两名玩家轮流行动。
在每一次行动中,可以任选一张矩形网格纸,沿着某一行或某一列的格线,把它剪成两部分。
首先剪出 1×1 的格纸的玩家获胜。
两名玩家都采取最优策略行动,求先手是否能获胜。
提示:开始时只有一张纸可以进行裁剪,随着游戏进行,纸张被裁剪成 2,3,… 更多张,可选择进行裁剪的纸张就会越来越多。
题解:
常规的博弈论做法,用记忆化搜索来求每个状态的后继状态的sg值,利用mex求出本状态的值
本题与常规的博弈论不同点在于,一般博弈论是一方无法操作时结束比赛,而本题是达到某一状态时结束比赛。常规来说我们要将纸裁成两部分,循环应该从1开始到n,但是本题不行,因为题目说了先剪除1 * 1的获胜,也就是说如果我们如果我们先剪除一个边为1,那么对手就可以借此剪除1 * 1,所以本题的最终状态是无论怎么操作都会剪除一个边为1,即除了1其他都不能剪除则输,所能减的范围是2,n-1,如果不能操作,则必败
for ( rg int i = 1; i <= n; ++i ){ vis [ sG ( i, c ) ^ sG ( n-i, c ) ] = true; }
本题巧妙的将最终状态进行定义,方便了代码的实现
代码:
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
#define MAXN 205
using namespace std;
typedef long long ll;
int N,M;
int sg[MAXN][MAXN];
int dfs(int n, int m){
if(n > m) swap(n,m);
if(sg[n][m]!=-1) return sg[n][m];
if(n==1 && m==1) return sg[n][m] = 0;
//cerr<<"dfs: "<<n<<" "<<m<<endl;
int vis[MAXN];
memset(vis, 0, sizeof(vis));
int ans;
for(int x=2;x<n-1;x++){
ans = dfs(x,m)^dfs(n-x,m);
vis[ans] = 1;
}
for(int y=2;y<m-1;y++){
ans = dfs(n,y)^dfs(n,m-y);
vis[ans] = 1;
}
for(int i=0;i<=2*M;i++){
if(!vis[i]) return sg[n][m] = i;
}
}
int main(){
memset(sg, -1, sizeof(sg));
while(cin>>N>>M){
if(N > M) swap(N, M);
if(dfs(N,M)==0) puts("LOSE");
else puts("WIN");
}
return 0;
}
以上是关于Acwing 219. 剪纸游戏的主要内容,如果未能解决你的问题,请参考以下文章