GMOJ P2642 【游戏】

Description

给你一个正整数 $n$ 和一个 $n \times n$ 的矩阵 $a$,有两个人轮流对这个矩阵进行操作,每次可以删掉最后一行或最后一列,但必须要保证所删的行或列的和是偶数。当一个人无法操作时这个人就输了。

现在请你求出在双方都使用最优策略的情况下,先手是否有必胜策略,有则输出 $W$ ,否则输出 $L$

$1 \leq n \leq 1000,1 \leq T \leq 5$ 。

$\text{保证每一行或每一列的和不会超过};2 \times 10^9$ 。

Solution

  • 方法一

考虑使用 DP 来解题。

设 $f[i][j]=0/1$ 表示当剩下 $i$ 行 $j$ 列时先手 必败/必胜 。

为了方便,然后显然有转移方程:

$f[i][j]=f[i][j]|(!f[i-1][j])\quad\quad\quad((\sum_{k=1}^{j}a_{i,k});\mod;2=0)$

$f[i][j]=f[i][j]|(!f[i][j-1])\quad\quad\quad((\sum_{k=1}^{i}a_{k,j});\mod;2=0)$

求和那里可以初始化一下。

然后这道题目就做完了,时间复杂度 $O(Tn^2)$ 。

  • 方法二

考虑使用 DFS 来解题。

先将整个图的横向和纵向做一遍前缀和,用 DFS 做一遍游戏过程即可。

时间复杂度 $O(Tn^2)$ ,具体的细节见 代码 部分。

然后这道题目就做完了。

Code

  • 方法一
1
#include <cstdio>
2
#include <cstring>
3
int f[1001][1001],a[1001][1001];
4
int sumx[1001][1001],sumy[1001][1001];
5
int main()
6
{
7
    int T=0;
8
    scanf("%d",&T);
9
    while(T--)
10
    {
11
        int n=0;
12
        scanf("%d",&n);
13
        for(int i=1;i<=n;i++)
14
        {
15
            for(int j=1;j<=n;j++)
16
            {
17
                int x=0;
18
                scanf("%d",&x);
19
                a[i][j]=x;
20
                sumx[i][j]=sumx[i][j-1]+x;
21
                sumy[j][i]=sumy[j][i-1]+x;
22
            }
23
        }
24
        memset(f,0,sizeof(f));
25
        for(int i=1;i<=n;i++)
26
        {
27
            for(int j=1;j<=n;j++)
28
            {
29
                if( sumx[i][j]%2==0 )
30
                {
31
                    f[i][j]= f[i][j] | (!f[i-1][j]) ;
32
                }
33
                if( sumy[j][i]%2==0 )
34
                {
35
                    f[i][j]= f[i][j] | (!f[i][j-1]) ;
36
                }
37
            }
38
        }
39
        printf("%c\n",f[n][n]==1?'W':'L');
40
    }
41
    return 0;
42
}
  • 方法二
1
#include<cstdio>
2
int t,n,a[1001][1001],sum[1001][1001][2];
3
inline bool dfs(int nx,int x,int y)
4
{
5
    if(nx==1)
6
    {
7
        if(x==0||y==0)return false;
8
        if(!sum[x][y][1])
9
            if(dfs(2,x-1,y)==true)return true;
10
        if(!sum[x][y][0])
11
            if(dfs(2,x,y-1)==true)return true;
12
        return false;
13
    }
14
    else
15
    {
16
        if(x==0||y==0)return true;
17
        if(!sum[x][y][1])
18
            if(dfs(1,x-1,y)==false)return false;
19
        if(!sum[x][y][0])
20
            if(dfs(1,x,y-1)==false)return false;
21
        return true;
22
    }
23
}
24
int main()
25
{
26
    scanf("%d",&t);
27
    while(t--)
28
    {
29
        scanf("%d",&n);
30
        for(int i=1;i<=n;i++)
31
        {
32
            for(int j=1;j<=n;j++)
33
            {
34
                scanf("%d",&a[i][j]);
35
                sum[i][j][1]=(sum[i][j-1][1]+a[i][j])%2;
36
                sum[i][j][0]=(sum[i-1][j][0]+a[i][j])%2;
37
            }
38
        }
39
        if(dfs(1,n,n)==true)
40
        {
41
            printf("W\n");
42
        }
43
        else
44
        {
45
            printf("L\n");
46
        }
47
    }
48
    return 0;
49
}