题意
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,否则就是原元素。
- 问题
- 为什么不能直接在发现可消除元素后将它们都变为0?
我最开始就是这么写的。问题就在于:一个元素可能被多次消除。如果在第一次发现它可被消除后就将它直接改为0存储,则在之后的与其相关的其他元素作为中心元素进行判定时,就无法知道该点的原元素是什么,当前待判定的组合是否满足消除。
因此只能折中利用一个布尔数组来记录可消除的元素,而保留其原元素来进行接下来的判断。
- 如何将三个以上的相同元素全都标记?
正因为题目给出的条件是三个及以上的连续相同元素都可消除。因此在发现一个与中心元素相等的相邻元素后,应该对其方向上剩下的所有元素进行判定,直到遇到不满足要求的。
不停的嵌套循环是肯定不合理的,因为无法确定具体循环的次数。而其实每次求相同方向上的下一个元素的方法是相同的,因此就可以用while来总结规律实现循环求解相同方向上下一个元素坐标。
总结
- 两题ac主要还是因为第二题不难😐
- 这次就吸取教训比较耐心地调试了,虽然我觉得很大部分功劳在于测试样例给的好,第一遍调试就直接发现问题了🧐
代码
//
// 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;
}