来源:JZOJ
题目描述
由于手上(更确实的,蹄子上)有大把的空余时间, 的农场里的奶牛经常玩电子游戏消磨时光。她们最爱的游戏之一是基于一款流行的电子游戏 的奶牛版;名称当然叫做 。
是在一块又高又窄的棋盘上进行的游戏,高 格,宽 格。 这是一个 的棋盘的例子:
0000000000
0000000300
0054000300
1054502230
2211122220
1111111223
每个格子或者是空的(用 表示),或者是九种颜色之一的干草捆(用字符 表示)。重力会使得干草捆下落,所以没有干草捆的下方是 。
如果两个格子水平或垂直方向直接相邻,并且为同一种非 颜色,那么这两个格子就属于同一个连通区域。任意时刻出现至少 个格子构成的连通区域,其中的干草捆就会全部消失,变为 。如果同时出现多个这样的连通区域,它们同时消失。随后,重力可能会导致干草捆向下落入某个变为 的格子。由此形成的新的布局中,又可能出现至少 个格子构成的连通区域。若如此,它们同样也会消失(如果又有多个这样的区域,则同时消失),然后重力又会使得剩下的方块下落,这一过程持续进行,直到不存在大小至少为K的连通区域为止。
给定一块 棋盘的状态,输出这些过程发生之后最终的棋盘的图案。
解题思路
- 这道题分为几个步骤来做
- 先求连通块,如果有 的,那么就清 ,然后下落;
- 思路很简单,但是代码调试还是有一点难度的(千万不要手贱 )
美妙的 时间、
#include <bits/stdc++.h>
using namespace std;
int fx[4]={0,0,1,-1};
int fy[4]={1,-1,0,0};
int n,k,sum=0;
int f[105][105],a[105][105];
void dfs(int x,int y,int s) //统计连通块
{
f[x][y]=1;
for (int i=0;i<4;i++)
{
int xx=x+fx[i],yy=y+fy[i];
if (xx<1 || xx>n || yy<1 || yy>10) continue;
if (a[xx][yy]!=s || f[xx][yy]) continue;
sum++;
dfs(xx,yy,s);
}
}
void remove(int x,int y,int s) //清0
{
f[x][y]=1;
for (int i=0;i<4;i++)
{
int xx=x+fx[i],yy=y+fy[i];
if (xx<1 || xx>n || yy<1 || yy>10) continue;
if (a[xx][yy]!=s || f[xx][yy]) continue;
remove(xx,yy,s);
}
a[x][y]=0;
}
void drop() //处理下落
{
for (int i=n;i>=1;i--)
for (int j=1;j<=10;j++)
{
if (a[i][j]!=0)
{
int k=i;
while (k<n && !a[k+1][j]) k++;
if (k!=i)
{
a[k][j]=a[i][j];
a[i][j]=0;
}
}
}
}
void work()
{
bool flag=1;
while (flag) //如果没有到最终状态
{
flag=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=10;j++)
{
if (!a[i][j]) continue;
memset(f,0,sizeof(f));
sum=1;
dfs(i,j,a[i][j]);
if (sum>=k) //找到大于等于k的连通块
{
flag=1;
memset(f,0,sizeof(f));
remove(i,j,a[i][j]); //清0
}
}
if (flag)
{
drop(); //如果有清0的情况就执行下落
}
}
}
int main()
{
freopen("mooyo.in","r",stdin);
freopen("mooyo.out","w",stdout);
scanf("%d %d",&n,&k);
for (int i=1;i<=n;i++)
for (int j=1;j<=10;j++)
{
scanf("%1d",&a[i][j]);
}
work();
for (int i=1;i<=n;i++)
{
for (int j=1;j<=10;j++) printf("%d",a[i][j]);
printf("\n");
}
return 0;
}