链接:code force
中文链接:洛谷P5121
题意:
Mooyo Mooyo 是在一块又高又窄的棋盘上进行的游戏,高N格,宽 10 格。 这是一个 N=6 的棋盘的例子:
0000000000
0000000300
0054000300
1054502230
2211122220
1111111223
每个格子或者是空的(用 0 表示),或者是九种颜色之一的干草捆(用字符1…9 表示)。重力会使得干草捆下落,所以没有干草捆的下方是 0。
如果两个格子水平或垂直方向直接相邻,并且为同一种非 0 颜色,那么这两个格子就属于同一个连通区域。任意时刻出现至少 K 个格子构成的连通区域,其中的干草捆就会全部消失,变为 0。如果同时出现多个这样的连通区域,它们同时消失。随后,重力可能会导致干草捆向下落入某个变为 0的格子。由此形成的新的布局中,又可能出现至少 K个格子构成的连通区域。若如此,它们同样也会消失(如果又有多个这样的区域,则同时消失,然后重力又会使得剩下的方块下落,这一过程持续进行,直到不存在大小至少为K的连通区域为止。
给定一块 Mooyo Mooyo 棋盘的状态,输出这些过程发生之后最终的棋盘的图案。(摘自洛谷,链接如上)
数据大小:
1<=N <=100
1<=k<=10N
思路:
这道题目其实就类似于一个消消乐。。。先瞬间消掉连起来超过k长度的方块(把1~9看成不同颜色的方块),然后下落,再消,直到消不了,输出答案就行。
因为数据不大所以我们可以模拟来做。
模拟的过程有:
1.查找连在一起并且超过k长度的联通方块
2.消去联通方块
3.模拟消去方块后的下落过程
4.重复1~3直到没有超过k长度的联通方块,就结束
1、2都是搜图,可以想到深搜,其实就是深搜,一搜图,二搜标记数组消图
ac代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
//图大小是N*10 N<=100
char map[105][11];//图
int vis[105][11];//标记数组
int v[4][2] = {0,1,1,0,0,-1,-1,0};//四个搜索方向
int n,k;
int sum;
//查map图
//传入当前的坐标和颜色
void search1(int x,int y,char c)
{
vis[x][y] = 1;//用vis数组标记已经查过图中这个坐标的点了
for(int i = 0;i<4;i++)
{
int xx = x+v[i][0];
int yy = y+v[i][1];
if(xx<0 || yy<0 || xx>=n || yy >= 10 || map[xx][yy]!=c || vis[xx][yy])continue;
sum++;
search1(xx,yy,c);
}
}
//清map图
void dfs(int x,int y)
{
if(vis[x][y])//把map图里面的消掉的同时把vis标记去掉
{
map[x][y] = '0';
vis[x][y] = 0;
}
for(int i = 0;i<4;i++)
{
int xx = x+v[i][0];
int yy = y+v[i][1];
if(xx<0 || yy<0 || xx>=n || yy >=10)continue;
if(vis[xx][yy])dfs(xx,yy);
}
}
//清vis数组,wa第二个就是因为这个。。。
void dfs1(int x,int y)
{
if(vis[x][y])vis[x][y] = 0;
for(int i = 0;i<4;i++)
{
int xx = x+v[i][0];
int yy = y+v[i][1];
if(xx<0 || yy<0 || xx>=n || yy >=10)continue;
if(vis[xx][yy])dfs1(xx,yy);
}
}
//搜图函数
int seamap()
{
int flag = 0;//如果搜完图之后没有一个颜色长度是大于k的,就可以结束并输出图了
for(int i = 0;i<n;i++)
{
for(int j = 0;j<10;j++)
{
//if(j && map[i][j] == map[i][j-1])continue;
//if(i && map[i][j] == map[i-1][j])continue;
if(map[i][j]!='0')
{
sum = 1;//当前一个点,所以初始化为1
search1(i,j,map[i][j]);
if(sum>=k)//满足条件就清图,不满足就把vis数组清了,不影响下一次的标记
{
flag = 1;
dfs(i,j);
}
else
dfs1(i,j);
}
}
}
if(flag)return 1;
else return 0;
}
int main()
{
scanf("%d %d",&n,&k);
for(int i = n-1;i>=0;i--)
scanf("%s",map[i]);
while(seamap())
{
//模拟下落过程//
for(int i = 0;i<10;i++)
{
string s;
int len = 0;
//记下当前列的非0字符,存到s
for(int j = 0;j<n;j++)
if(map[j][i]!='0')
{
s += map[j][i];//看大佬代码学的,很好用
len++;
}
for(int j = 0;j<n;j++)
{
if(j<len)
map[j][i] = s[j];
else
map[j][i] = '0';
}
}
}
for(int i = n-1;i>=0;i--)
printf("%s\n",map[i]);
return 0;
}