N*M bulbs
Accepts: 71
Submissions: 249
Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
N*M个灯泡排成一片,也就是排成一个N*M的矩形,有些开着,有些关着,为了节约用电,你要关上所有灯,但是你又很懒。 刚好有个熊孩纸路过,他刚好要从左上角的灯泡走去右下角的灯泡,然后离开。 但是毕竟熊孩纸,熊孩纸在离开一个灯泡之前,一定会动一下当前开关,也就是开的变关,关的变开。 想问你可不可能关完所有的灯,同时熊孩纸也可以到达右下角的灯泡,然后离开。
输入描述
第一行T,表示T组数据。 接下来T组数据: 每组数据,第一行N,M,后面一个N*M的01矩阵,表示灯泡的初始开关状态,0表示关,1表示开。 1≤T≤10 1≤N,M≤1000
输出描述
每组数据,如果可以输出"YES",否则输出"NO"。
输入样例
1 1 5 1 0 0 0 0
输出样例
YES
Hint
孩子的路径是:123234545 刚好除了第一盏灯,其他灯都只经过偶数次。
官方题解:
我们发现操作数跟n+m-1同奇偶,那是不是当1的个数跟n+m-1同奇偶是就是YES呢?
答案是肯定的,我们这样看:首先将棋盘黑白染色,就是若(i,j)格子,若(i+j)是奇数,那么就是黑格子,否则就是白格子。
我们发现我们可以通过一种操作使得从一个格子走到斜方向的任意一个格子。
这个操作很简单,我们假设一个2*2的棋盘:
1 2
3 4
我们这样走:1->2->1->2->4, 1就直接走到4了,而且不产生任何操作。
也就是同色格子可以互相到达。
然后我们发现如果要操作一个开关,那么最后所在格子颜色一定会改变。
同上面这个例子:
1 2
3 4
假设我们要操作2这个格子。
1->2->1->3
我们成功操作了2这个格子,但是从白格子转到黑格子了。
也就是说,假设格子(n,m)下面有个格子(n+1,m)是最后终点,然而每次操作一个格子需要改变一次颜色。
也就是我们从(1,1)改变了若干次颜色后,最后颜色一定要和(n+1,m)相同。
也就是说1的个数要和(n+1+m)(n+1+m)同奇偶。否则无解。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
#define INF 0x3fffffff
const int maxn = 1005;
int n, m, num;
int val[maxn][maxn];
void input()
{
int i, j;
scanf("%d%d", &n, &m);
num = 0;
for (i = 1; i <= n; i++)
{
for (j = 1; j <= m; j++)
{
scanf("%d", &val[i][j]);
num += val[i][j];
}
}
}
void solve()
{
if ((num & 1) == ((n + m + 1) & 1))
{
puts("YES");
}
else
{
puts("NO");
}
}
int main()
{
//freopen("i.txt", "r", stdin);
//freopen("o.txt", "w", stdout);
int t;
scanf("%d", &t);
while (t--)
{
input();
solve();
}
//system("pause");
return 0;
}