[USACO18DEC]Mooyo Mooyo(C题)

链接: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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值