题解 P1312 【Mayan游戏】

· · 题解

题解

传送门:透彻

此题就相当与是一道大型搜索模拟题,需要耐心,极考验码力;

因为代码比较长,所以建议大家多写函数,尽量不要都写在一起;

提前交代数组

int map[N][N]; //输入的图

int ans[N][5]; //输出的答案

int last[N][N][N]; //后面会讲

bool xiao[N][N]; //后面会讲

下面我讲一下其中的核心函数:

1.copy(复制):

我们要把当前的原始状态复制

为什么要复制呢,回溯时要用;

但不能使用二维数组了,要定义一个三维数组

last[d][i][j]:第d步时在i行j列的原状态;

void copy(int x){
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
        last[x][i][j]=map[i][j];
}

2.update(更新游戏的状态):

这个比较简单,就是把该掉下去的掉下去;

定义一个x为这个这个方块下0的个数,然后模拟一下;

void update(){
    for(int i=1;i<=5;i++){
        int x=0;
        for(int j=1;j<=7;j++){
            if(!map[i][j])x++;
            else{
                map[i][j-x]=map[i][j];
                map[i][j]=0;
            }
        }
    }
}

3.remove(消除):

题目要求一定要行或列连续3个才能消除;

但一定不能遇到3个连续的就消;

例如:

bool remove(){
    int flag=0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++){
            if(i-1>=1&&i+1<=5&&map[i][j]==map[i-1][j]&&map[i][j]==map[i+1][j]&&map[i][j]){
                xiao[i-1][j]=1;xiao[i+1][j]=1;xiao[i][j]=1;flag=1;
            }
            if(j-1>=1&&j+1<=7&&map[i][j]==map[i][j+1]&&map[i][j]==map[i][j-1]&&map[i][j]){
                xiao[i][j]=1;xiao[i][j+1]=1;xiao[i][j-1]=1;flag=1;
            }
        }
    if(!flag)return 0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
        if(xiao[i][j]){
            xiao[i][j]=0;
            map[i][j]=0;
        } 
    return 1;
}

图5中的要是先消3个,那剩下的就不能消了,就WA了;

我枚举的i,j是中间方块的坐标;

而且使用的是bool型,为了后面判断是否可以继续去消;

4.move (移动):

移动比较简单;就是用到了之前函数;

要注意,可能消除后还可以更新,所以要使用while循环;

void move(int i,int j,int x){
    int tmp=map[i][j];
    map[i][j]=map[i+x][j];
    map[i+x][j]=tmp;
    update();
    while(remove())update();
}

5.check(判断是否都消除了):

这个更简单了;

因为所有方块都掉落了,所以直接判断最后一行都为0就行了;

bool check(){
    for(int i=1;i<=5;i++)
        if(map[i][1])return 0;
    return 1;
}

DFS的剪枝:

1.相同颜色的方块可以跳过(显而易见);

2.还有一个比较难想的剪枝:

结论:只有右边有方块才move,左边没有方块才move;

证明(自己瞎写的):

(你正在搜i列)若左面有方块,那么你会在搜i-1列时将其右移,和你在i列时左移是等效的,所以可以减掉;

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cctype>
#include<cstdlib>
#define ll long long
#define N 10
using namespace std;
int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int n,map[N][N],ans[N][5],last[N][N][N],xiao[N][N];
bool remove(){
    int flag=0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++){
            if(i-1>=1&&i+1<=5&&map[i][j]==map[i-1][j]&&map[i][j]==map[i+1][j]&&map[i][j]){
                xiao[i-1][j]=1;xiao[i+1][j]=1;xiao[i][j]=1;flag=1;
            }
            if(j-1>=1&&j+1<=7&&map[i][j]==map[i][j+1]&&map[i][j]==map[i][j-1]&&map[i][j]){
                xiao[i][j]=1;xiao[i][j+1]=1;xiao[i][j-1]=1;flag=1;
            }
        }
    if(!flag)return 0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
        if(xiao[i][j]){
            xiao[i][j]=0;
            map[i][j]=0;
        } 
    return 1;
}

bool check(){
    for(int i=1;i<=5;i++)
        if(map[i][1])return 0;
    return 1;
}
void copy(int x){
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
        last[x][i][j]=map[i][j];
}
void update(){
    for(int i=1;i<=5;i++){
        int wow=0;
        for(int j=1;j<=7;j++){
            if(!map[i][j])wow++;
            else{
                if(!wow)continue;
                map[i][j-wow]=map[i][j];
                map[i][j]=0;
            }
        }
    }
}
void move(int i,int j,int x){
    int tmp=map[i][j];
    map[i][j]=map[i+x][j];
    map[i+x][j]=tmp;
    update();
    while(remove())update();
}

void dfs(int x){
    if(check()){
        for(int i=1;i<=n;i++){
            if(i!=1)printf("\n");
            for(int j=1;j<=3;j++)
            printf("%d ",ans[i][j]);
        }
        exit(0);
    }
    if(x==n+1)return;
    copy(x);
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++){
            if(map[i][j]){
                if(i+1<=5&&map[i][j]!=map[i+1][j]){
                move(i,j,1);
                ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=1;
                dfs(x+1);
                for(int i=1;i<=5;i++)
                    for(int j=1;j<=7;j++)
                    map[i][j]=last[x][i][j];
                ans[x][1]=-1;ans[x][2]=-1;ans[x][3]=-1;
            }
            if(i-1>=1&&map[i-1][j]==0){
                move(i,j,-1);
                ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=-1;
                dfs(x+1);
                for(int i=1;i<=5;i++)
                    for(int j=1;j<=7;j++)
                    map[i][j]=last[x][i][j];
                ans[x][1]=-1;ans[x][2]=-1;ans[x][3]=-1;
            }
            }
        }
}
int main()
{
//    freopen("Manya.in","r",stdin);
//    freopen("Manya.out","w",stdout);
    n=read();
    for(int i=1;i<=5;i++){
        for(int j=1;j<=8;j++){
            int x=read();
            if(x==0)break;
            map[i][j]=x;
        }
    }
    memset(ans,-1,sizeof(ans));
    dfs(1);
    puts("-1");
    return 0;
}