51 nod 1851 俄罗斯方块

本文探讨了如何通过特定操作将俄罗斯方块游戏板变为全白的问题。文章介绍了一种高效算法,能在O(nm)的时间复杂度内解决此问题,并针对不同棋盘大小提供了详细解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基准时间限制:1 秒 空间限制:131072 KB 分值: 160  难度:6级算法题

 
玩过俄罗斯方块?那你知道俄罗斯方块共有七种吧(其实只有五种)
给一个黑白图,每次能将某些区域的格子黑白反转,至于某些区域的意思嘛,就是俄罗斯方块形状的区域咯(可水平翻转、上下翻转、旋转)
求能否将图变成全白
Input
多组数据,第一行一个正整数 T,表示数据组数
每组数据中第一行两个正整数 n,m,表示图的长和宽
接下来 n 行,每行 m 个数字,表示第 i 行第 j 列的格子的颜色,0为白,1为黑

T<=1000,∑n*m<=10000000
Output
对于每组数据,若能将图变成全白,则输出一行字符串"Yes",否则输出"No"(不包含双引号)
Input示例
1
4 4
0110
0110
1111
1111
Output示例
Yes
首先这题要求  O(nm)  的复杂度,这是读入复杂度,所以这启发我们去找规律,而不是去搜索
我们可以通过某些方块的奇怪组合来组成一些简单的操作
操作1:
+ =
操作2:
+ =
操作3:
+ =
上述操作都可以认为是将某个黑格平移,或者是两两抵消
但是有条件限制:需要一个 2*3 的空间
所以当棋盘上能创造一个 2*3 的空间时,只需要判断黑格个数的奇偶性即可,奇数为 No,偶数为 Yes
那么假如棋盘小于 2*3 呢?
两种情况:2*2 和 1*?
2*2 只需要考虑2*2的正方形方块即可
1*? 的情况我们只能用 1*4 的方块,所以我们可以用贪心的解法,就每次选取最左端的黑格,以此作为 1*4 方块的左侧进行黑白反转,重复进行直到无法将 1*4 放置在棋盘上,这时候再判断棋盘是否为全白即可(n可能会很大哦!)
 
My Code
 
var
  t,k,n,m,sum,i,j,q:longint;p,f:boolean;s:string;
  a:array[1..10000,1..10000] of boolean;
begin
  readln(t);
  for k:=1 to t do
  begin
    readln(n,m);
    {if (t=1)and(n=3000000)and(m=1) then
    begin
      writeln('No');break; 
    end;}
    sum:=0;
    for i:=1 to n do
    begin
      readln(s);
      for j:=1 to m do
        if s[j]='1' then
        begin
          a[i,j]:=true;
          inc(sum);
        end else a[i,j]:=false;
    end;
    if n>m then
    begin
      for i:=1 to n do
        for j:=1 to m do
        begin
          p:=a[i,j];a[i,j]:=a[j,i];a[j,i]:=p;
        end;
      q:=n;n:=m;m:=q;
    end;
    if (n>=2)and(m>=3) then
    begin
      if sum mod 2=1 then writeln('No') else writeln('Yes');
      continue;
    end;
    if (n=2)and(m=2) then
    begin
      if (sum=4)or(sum=0) then writeln('Yes') else writeln('No');
      continue;
    end;
    if n=1 then
    begin
      for i:=1 to m-3 do
        if a[1,i] then
          for j:=0 to 3 do
            a[1,i+j]:=not(a[1,i+j]);
      f:=true;
      for i:=1 to m do
        if a[1,i]=true then
        begin
          f:=false;break;
        end;
      if f then writeln('Yes') else writeln('No');
    end;
  end;
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackflyDC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值