网易互娱2017实习生招聘游戏研发工程师在线笔试第二场(一起消消毒)

3 篇文章 0 订阅
3 篇文章 0 订阅

题意分析:

(1)题目是模拟开心消消乐的游戏逻辑,当交换两个相邻的图片时,如果交换后的面板中有连续的三个以上的相同的图片(拍成行或列),那么这些排列成行或列的相同的图形将消失,上面的图形将下落填充中间的空白,下落后有可能再次出现可消除的情况,于是同以上步骤,一直到最后没有可消除为止,求这次交换操作一共可消去多少个图形。

(2)题目对游戏的原型进行了简化:即消去一部分图形之后,没有新的图形产生,下落完成后,空余的部分用空白替代,图形用字符代替。我们可以先从第一个非‘.’的字符出发,作如下操作:从这个字符开始左右扫描,找出这一行是否有连续的三个以上(包括本字符)字符和本字符相同,设这一可消行的左右边界为(b,d);如没有连续的三个及以上,则从这个字符上下开始扫描。如找到可消列,设列的边界为(a,c)

(3)注意:这里并非找到连续的三个及以上相同的字符就立即消除,而是要顺着这个可消行(列)依次向上下(左右)继续搜索,找出在这个行(列)上其他的字符为中心上下扩展搜索的可消除列(行)的字符,称为"枢轴",见下图:


(4)如图:找到可消区域的枢轴之后,沿着枢轴找到上下边界(a,c),左右边界(b,d),然后删除这个边界内的图形;图一是正确的消除,反之,如果一开始找到连续的三个及以上的图形就删除,就会导致图二的错误,会由于消除枢轴之后,右边一列下落之后缺少一个,不能消除。

(5)设枢轴为arr[x][y],按照(4)消除之后,就需要将在x行以上(a,c)列之间的列向下移动一个位置,y列中空格上面的字符集体向下移动(d-1-b)个位置

(6)消除并移动之后,就会出现新的面板状态,这时有可能新的面板状态中由于图形的移动会出现新的可消行(列),于是我们又需要从头开始检索,如果存在可消行(列),就执行以上的重复步骤;反之,就开始检索下一个位置。这就是典型的回溯

可能坑点:

(1)没有找到枢轴,只找到可消行列就开始消除

(2)一定要注意可消行列的边界,本算法中边界不包括a、c、b、d,很容易不注意就弄错边界

(3)回溯的条件是:这一轮没有找到可消的行列,反应在数字上就是连续行、列相同的图形个数分别小于3,注意一定要是分别小于3!!!这里很容易出错。

(4)消除的时候下落距离要弄清

#include <iostream>
#include <stdio.h>

using namespace std;

int N,M;
char arr[20][20];
int res=0;
void cal()
{
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<M;j++)
        {
            //遇到非空格字符的时候才开始判断
            if(arr[i][j]!='.')
            {
                int x=i,y=j;//最终消除区域的中心
                int a=i,b=j,c=i,d=j;
                int sum=0;
                int temp=0;
                //先开始纵向搜索
                while((--a)>=0&&arr[a][j]==arr[i][j])temp++;
                while((++c)<N&&arr[c][j]==arr[i][j])temp++;
                //若纵向搜索可找到消除的列
                if(temp>=2)
                {
                    sum+=temp;
                    temp=0;
                    int maxum=0;
                    //开始在这个纵向列上以每个字符为中心开始横向搜索
                    for(int k=a+1;k<=c;k++)
                    {
                        int cnt=0;
                        int b1=j,d1=j;
                        while((--b1)>=0&&arr[k][b1]==arr[i][j])cnt++;
                        while((++d1)<M&&arr[k][d1]==arr[i][j])cnt++;
                        //若横向搜索可找到消除的行
                        if(cnt>=2&&cnt>maxum)
                        {
                            maxum=cnt;
                            //更新中心点
                            x=k;
                            y=j;
                            //更新左右边界
                            b=b1;
                            d=d1;
                        }
                    }
                    sum+=maxum;
                }
                else//若纵向搜索找不到消除的列
                {
                   temp=0;
                   a=i,b=j,c=i,d=j;
                   //开始重新横向搜索
                   while((--b)>=0&&arr[i][b]==arr[i][j])temp++;
                   while((++d)<M&&arr[i][d]==arr[i][j])temp++;
                   //若横向搜索可找到消除的行
                   if(temp>=2)
                   {
                       sum+=temp;
                       temp=0;
                       int maxum=0;
                       //开始在这个横向行上以每个字符为中心开始纵向搜索
                       for(int k=b+1;k<d;k++)
                       {
                           int cnt=0;
                           int a1=i,c1=i;
                           while((--a1)>=0&&arr[a1][k]==arr[i][j])cnt++;
                           while((++c1)<N&&arr[c1][k]==arr[i][j])cnt++;
                           //若纵向搜索可找到消除的列
                           if(cnt>=2&&cnt>maxum)
                           {
                               maxum=cnt;
                               //更新中心点
                               x=i;
                               y=k;
                               //更新上下边界
                               a=a1;
                               c=c1;
                           }
                       }
                       sum+=maxum;
                   }
                }
                //若符合消除的条件
                if(sum>=2)
                {
                    res+=sum;
                    sum=0;
                    res++;
                    //若纵向上有消除的列,则消除后合并
                    if(c-a>=3)
                    {
                        for(int e=a;e>=0;e--)arr[e+c-1-a][y]=arr[e][y];
                        for(int e=0;e<c-a-1;e++)arr[e][y]='.';
                    }
                    //若横向上有消除的行,则消除后合并
                    if(d-b>=4)
                    {
                        for(int e=b+1;e<d;e++)
                        {
                            for(int f=x-1;f>=0;f--)arr[f+1][e]=arr[f][e];
                            arr[0][e]='.';
                        }
                    }
                    //开始向下回溯
                    cal();
                }
            }
        }
    }
}
int main()
{
    int S,x0,y0,x1,y1;
    cin>>S;
    while(S--)
    {
        cin>>N>>M;
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<M;j++)cin>>arr[i][j];
        }
        scanf("%d %d %d %d",&x0,&y0,&x1,&y1);
        char temp=arr[x0][y0];
        arr[x0][y0]=arr[x1][y1];
        arr[x1][y1]=temp;

        cal();
        printf("%d\n",res);
        res=0;
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值