Acwing 219. 剪纸游戏

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Acwing 219. 剪纸游戏相关的知识,希望对你有一定的参考价值。

【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. 剪纸游戏的主要内容,如果未能解决你的问题,请参考以下文章

关于在各浏览器中插入音频文件的html代码片段

AcWing 1813. 方块游戏(暴力枚举)

博弈论Nim游戏:台阶集合拆分(AcWing)

Acwing 1084. 数字游戏 II

春季每日一题打卡day2 —— AcWing 435. 传球游戏

AcWing 国王游戏