[csp模拟3] T2—— 消消乐大师—Q老师

题意

Q老师是个很老实的老师,最近在积极准备考研。Q老师平时只喜欢用Linux系统,所以Q老师的电 脑上没什么娱乐的游戏,所以Q老师平时除了玩Linux上的赛车游戏SuperTuxKart之外,就是喜欢 消消乐了。

游戏在一个包含有n 行m 列的棋盘上进行,棋盘的每个格子都有一种颜色的棋子。当一行或一列 上有连续三个或更多的相同颜色的棋子时,这些棋子都被消除。当有多处可以被消除时,这些地 方的棋子将同时被消除。

一个棋子可能在某一行和某一列同时被消除。

由于这个游戏是闯关制,而且有时间限制,当Q老师打开下一关时,Q老师的好哥们叫Q老师去爬 泰山去了,Q老师不想输在这一关,所以它来求助你了!!

Input

输入第一行包含两个整数n,m,表示行数和列数 接下来n行m列,每行中数字用空格隔开,每个数字代表这个位置的棋子的颜色。数字都大于0.

Output

输出n行m列,每行中数字用空格隔开,输出消除之后的棋盘。(如果一个方格中的棋子被消除, 则对应的方格输出0,否则输出棋子的颜色编号。)

输入样例

INPUT1

4 5
2 2 3 1 2
3 4 5 1 4
2 3 2 1 3
2 2 2 4 4

INPUT2

4 5
2 2 3 1 2
3 1 1 1 1
2 3 2 1 3
2 2 3 3 3

输出样例

OUTPUT1

2 2 3 0 2
3 4 5 0 4
2 3 2 0 3
0 0 0 4 4

OUTPUT2

2 2 3 0 2
3 0 0 0 0
2 3 2 0 3
2 2 0 0 0

提示

在这里插入图片描述


分析

需要处理一些有点麻烦的特殊情况的分析题


  • 题目分析&解决方法

1. 题意

题目字有一、、多,但是还是很好理解。

意思就是当行或列中连续排列的相同元素个数大于等于3时,将这些元素变为0输出。同样一个元素可能同时存在行或列中的待消除组合中。

2. 方法

  • 如何找到可消除的元素

这个题目的关键就是处理与一个元素同行或同列中的相同元素。因此可以联想到迷宫问题中,计算一个点四个方向上邻接点的方法。也就是利用两个数组分别表示横纵坐标偏移量,循环四次计算分别得到当前元素的四个相邻元素坐标。

因此,我采取的方法是对矩阵中的所有元素依次进行操作。首先计算它们的相邻元素。

同样的是,得到相邻元素后,首先要判断的仍然是坐标是否合法。

不同的是,在这道题中,计算出来后对相邻点的判断条件:

只有当相邻的元素等于中心元素时,才会有进一步的操作。因为题目要求至少三个连续元素相同。

当某个方向上的相邻元素与中心元素相同后,接着依次判断该方向上的剩余的所有元素。直到遇到下标边界或是与中心元素不同的元素。将相邻的相同元素全部进行标记。

由于对一个中心元素,可能存在不止一个方向上存在可消除组合,因此只要出现可消除组合,就对当前中心元素进行标记。

  • 输出消除后的矩阵

因此,根据前面实现的方式,在输出时,对当前输出元素对应的标记数组进行判定。若已被标记,则输出0,否则就是原元素。


  • 问题
  1. 为什么不能直接在发现可消除元素后将它们都变为0?

我最开始就是这么写的。问题就在于:一个元素可能被多次消除。如果在第一次发现它可被消除后就将它直接改为0存储,则在之后的与其相关的其他元素作为中心元素进行判定时,就无法知道该点的原元素是什么,当前待判定的组合是否满足消除。

因此只能折中利用一个布尔数组来记录可消除的元素,而保留其原元素来进行接下来的判断。

  1. 如何将三个以上的相同元素全都标记?

正因为题目给出的条件是三个及以上的连续相同元素都可消除。因此在发现一个与中心元素相等的相邻元素后,应该对其方向上剩下的所有元素进行判定,直到遇到不满足要求的。

不停的嵌套循环是肯定不合理的,因为无法确定具体循环的次数。而其实每次求相同方向上的下一个元素的方法是相同的,因此就可以用while来总结规律实现循环求解相同方向上下一个元素坐标。


总结

  1. 两题ac主要还是因为第二题不难😐
  2. 这次就吸取教训比较耐心地调试了,虽然我觉得很大部分功劳在于测试样例给的好,第一遍调试就直接发现问题了🧐

代码

//
//  main.cpp
//  lab2
//
//

#include <iostream>
#include <queue>
using namespace std;

int board[31][31];
bool vis[31][31] = {false};
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int n = 0,m = 0;

int main()
{
    ios::sync_with_stdio(false);
    
    cin>>n>>m;
    
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= m ; j++ )
            cin>>board[i][j];
    
//    int x = 1,y = 1;
    bool judge = false;
    
        for( int x = 1 ; x <= n ; x++ )
            for( int y = 1 ; y <= m ; y++ )
            {
                
                judge = false;
                
                 for( int i = 0 ; i < 4 ; i++ )  //判断当前点的四个相邻点
                 {
                    int x1 = x + dx[i];
                    int y1 = y + dy[i];
                     
                    if( x1 > 0 && x1 <= n && y1 > 0 && y1 <= m )        //坐标合法
                    {
                         if( board[x1][y1] == board[x][y] )     //与中心点颜色一致
                         {
                             while(1)       //求相同方向的所有可消除点
                             {
                                 int x2 = x1 + dx[i];       //下一个相邻点
                                 int y2 = y1 + dy[i];
                                 
                                 if( x2 > 0 && x2 <= n && y2 > 0 && y2 <= m )   //坐标合法
                                 {
                                         if( board[x1][y1] == board[x2][y2] )  //颜色一致
                                         {
                                             judge = true;          //标记当前点存在可消除组合
                                             vis[x1][y1] = 1;     //将两个点都清零
                                             vis[x2][y2] = 1;
                                             
                                             x1 = x2;       //更新最外点坐标
                                             y1 = y2;
                                         }
                                         else
                                             break;
                                   }
                                   else
                                       break;
                                
                             }
                         }
                    }
                 }
                
                if( judge )                 //若当前点存在可消除组合,清零
                    vis[x][y] = 1;
            }
    
                    
    for( int i = 1 ; i <= n ; i++ )
    {
        for( int j = 1 ; j <= m ; j++ )
        {
            if( !vis[i][j] )
                cout<<board[i][j];
            else
                cout<<0;
            
            if( j < m )
                cout<<" ";
        }
        cout<<endl;
    }
    
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天翊藉君

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

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

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

打赏作者

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

抵扣说明:

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

余额充值