poj 2311 Cutting Game(sg函数)

【题目大意】:给出一个n*m的矩阵,两个人轮流切割...直到一方不能切割为止,问先手的胜负情况


【解题思路】:原本看完题目觉得很简单,直接裸敲了个dfs~~结果无情的TLE...然后想想看看sg函数,然后发现貌似自己有点明白了。

                            这道题的关键在于把问题转化为nim博弈...换句话话说一切博弈皆nim...

                            设(n,k)为当前状态...则其后继状态可以为很多种,而我们将其均视为(n,k)的后继状态时,我们可以得到sg(n,k)=sg(a)^sg(b)....;(a,b设为其后继状态)...

                            因此...转化为nim博弈问题...


【代码】:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define linf 1LL<<60
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

ll dp[220][220];

ll dfs(int n,int k){
    int vis[220];
    int x,y;
    if (dp[n][k]!=-1) return dp[n][k];    
    memset(vis,0,sizeof(vis));
    for (int i=2; i<=k-2; i++){
        y=dfs(n,i)^dfs(n,k-i);
        vis[y]=1;
    }
    for (int i=2; i<=n-2; i++){
        x=dfs(i,k)^dfs(n-i,k);
        vis[x]=1;
    }
    int cnt=0;
    while (vis[cnt]) cnt++;
    dp[n][k]=cnt;
    return cnt;
}

int n,k;

int main() {
    memset(dp,-1,sizeof(dp));
    dp[2][2]=0;
    dp[2][3]=0;
    dp[3][2]=0;
    while (~scanf("%d%d",&n,&k)){
        ll tmp=dfs(n,k);
        if (tmp<=0) cout << "LOSE" << endl;
        else cout << "WIN" << endl;
    }
    return 0;
}


你可能感兴趣的:(poj 2311 Cutting Game(sg函数))