前言
突然想起来,别个学校的OJ可能回重庆就登不了了(或者其他情况),所以赶忙跑来CSDN乖乖写博客OTZ
题目
Alice和Bob在玩一个游戏,游戏是在一个N*N的矩阵上进行的,每个格子上都有
一个正整数。当轮到Alice/Bob时,他/她可以选择最后一列或最后一行,并将其删除,但
必须保证选择的这一行或这一列所有数的和为偶数。如果他/她不能删除最后一行或最后一
列,那么他/她就输了。两人都用最优策略来玩游戏,Alice先手,问Alice是否可以必胜?
Input
第一行:T,表示数据组数
对于每组数据的第一行:N
接下来N行,每行N个数,描述这个矩阵
Output
如果Alice必胜输出W,否则输出L
Sample Input
2 2 2 4 6 8 3 5 4 2 1 5 9 7 3 8
Sample Output
L W
数据范围
100%数据满足
1<=N<=1000
保证每一行或每一列的和不会超过2*10^9
1<=T<=5
30%数据满足
1<=N<=5
50%数据满足
1<=N<=100
70%数据满足
1<=N<=500
分析
个人觉得可以算“博弈题”,SG函数地思想就可以搞定,只是实现方法不同(递归、递推、我是搜索),具体思想:
1)下一步到达的状态若都是必胜态,则当前为必败态
2)下一步到达的状态若有至少一个必败态,则当前为必胜态
先讲解自己的方法:
直接暴搜(本来是冲着骗分去的,没想到AC了),从Alice开始,和Bob交替着取,可以确定Alice胜负的状态:Bob本轮输了或者Alice本轮输了,不能确定就一直取,直到决出胜负或者取完
这个方法过了,自己觉得挺玄学的...
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1000;
int a[MAXN+5][MAXN+5];
int n;
bool flag;
void dfs(int id,int f1,int f2)//f1:行,f2:列
{
if(!f1||!f2)
{
if(id==1)
flag=false;
else
flag=true;
return ;
}
int sum1=0,sum2=0;
for(int i=1;i<=f2;i++)
sum1+=a[f1][i];
for(int i=1;i<=f1;i++)
sum2+=a[i][f2];
if(id==1)//Alice
{
if(sum1%2!=0&&sum2%2!=0)
{
flag=false;
return ;
}
else
{
if(sum1%2==0)
dfs(2,f1-1,f2);
if(sum2%2==0)
dfs(2,f1,f2-1);
}
}
else//Bob
{
if(sum1%2!=0&&sum2%2!=0)
{
flag=true;
return ;
}
else
{
if(sum1%2==0)
dfs(1,f1-1,f2);
if(sum2%2==0)
dfs(1,f1,f2-1);
}
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
dfs(1,n,n);
if(flag)
printf("W\n");
else
printf("L\n");
}
return 0;
}
有个同学的方法类似递推:
用f(i,j)表示 右上角:(1,1),左下角是(i , j)的矩阵的先手输(0)赢(1)状态
若当前矩阵是右上角:(1,1),左下角是(i , j),那么当前矩阵的状态f(i,j)可以由 f(i-1,j)和 f(i,j-1)得出,得出的思想就是SG函数——若有至少一个0则当前为1,若都为1则当前为0
(代码没有,懒,哈哈哈哈...我会改的,代码正在打呢你信不信qwq)