[博弈论/DP/成就感] 游戏

【问题描述】
     Alice和Bob在玩一个游戏,游戏是在一个N*N的矩阵上进行的,每个格子上都有一个正整数。当轮到Alice/Bob时,他/她可以选择最后一列或最后一行,并将其删除,但必须保证选择的这一行或这一列所有数的和为偶数。如果他/她不能删除最后一行或最后一列,那么他/她就输了。两人都用最优策略来玩游戏,Alice先手,问Alice是否可以必胜?
【输入格式】
    第一行:T,表示数据组数
    对于每组数据的第一行:N
    接下来N行,每行N个数,描述这个矩阵
【输出格式】
    如果Alice必胜输出W,否则输出L
【输入样例】
    2
    2
    2 4
    6 8
    3
    5 4 2
    1 5 9
    7 3 8
【输出样例】
    L
    W
【数据规模】
    100%数据满足 1<=N<=1000,1<=T<=5 保证每一行或每一列的和不会超过2*10^9
    30%数据满足 1<=N<=5
    50%数据满足 1<=N<=100
    70%数据满足 1<=N<=500
【我的思路】

    由于这题是模拟赛自己想出来的,又是第一次考这种类型的题目,就很有成就感,于是标签就多了“成就感” qwq,既然是自己想出来的,那就写简单一点了。

    每次删最后一排或最后一列,用 bool类型 f(x,y) 表示 (1,1) 到 (x,y) 这个矩阵先手 能(1) 否 (0) 必胜。

    如果f(x,y-1)=0,若最后一列可以删,就赢了,即f(x,y)=1;

    同理f(x-1,y)=0,若最后一排可以删,就赢了,即f(x,y)=1;

    若 前二者 都等于 1,那么 如果当前可以删,对手确定必胜;如果当前不能删,我方已经输了。

                               所以 这种情况无论如何必输。

    怎么看最后一排(列)能不能删呢?

    用二维前缀和维护就好了。

#include<bits/stdc++.h>
using namespace std;
long long a[1005][1005];
bool f[1005][1005];
int n,T;
int main()
{freopen("game.in","r",stdin);
 freopen("game.out","w",stdout);
 scanf("%d",&T);
for(int iii=1;iii<=T;iii++)
{

    scanf("%d",&n);
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      {
          scanf("%lld",&a[i][j]);
          a[i][j]=a[i-1][j]+a[i][j-1]-a[i-1][j-1]+a[i][j];
      }
    memset(f,0,sizeof(f));
    //printf("--------------------\n");
    /*
    for(int i=1;i<=n;i++)
    {
     for(int j=1;j<=n;j++)
      printf("%lld ",a[i][j]);            debug
     cout<<endl;
    }
    */ 
    //printf("--------------------\n"); 
    for(int i=1;i<=n;i++)
     for(int j=1;j<=n;j++)
      {
          if(f[i-1][j]==0) if((a[i][j]-a[i-1][j])%2==0) {f[i][j]=1;continue;}
          if(f[i][j-1]==0) if((a[i][j]-a[i][j-1])%2==0) {f[i][j]=1;continue;}
      }
    if(f[n][n]) printf("W\n");else printf("L\n");  
}
return 0;    
}

 

posted on 2018-10-24 17:17  Miniweasel  阅读(182)  评论(0编辑  收藏  举报

导航