DFS的剪枝:

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

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

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

证明(自己瞎写的):

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

//My AC Code:
#include <cstdio>
#include<cstdlib>
using namespace std;
int map[6][9],cf[6][6][8];
int xd[6][8];
int ans[6][5];
int n,js;
void cp(int x){
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
            cf[x][i][j]=map[i][j];
}
void update(){//检查 是否有消除,然后 让方块下落
    for(int i=1;i<=5;i++){
        int xa=0;
        for(int j=1;j<=7;j++){
            if(!map[i][j])xa++;
            else {
                if(!xa)continue;//因为如果空白为0 则表示当前方块下面没有被消除掉的方块
                map[i][j-xa]=map[i][j];
                map[i][j]=0;
            }
        }
    }
}
bool remv(){
    bool flag=false;
    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][j]==map[i+1][j]){
                xd[i-1][j]=1;xd[i][j]=1;xd[i+1][j]=1;flag=true;
            }
            if(j-1>=1&&j+1<=7&&map[i][j]&&map[i][j-1]==map[i][j]&&map[i][j]==map[i][j+1]){
                xd[i][j-1]=1;xd[i][j+1]=1;xd[i][j]=1;flag=true;
            }
        }
    }
    if(!flag)return 0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
            if(xd[i][j]){
                map[i][j]=0;
                xd[i][j]=0;
            }
    return 1;
}
void move(int a,int b,int c){
    int tp=map[a][b];
    map[a][b]=map[a+c][b];
    map[a+c][b]=tp;
    update();
    while(remv())update();
    /*
    移动后更新方块位置,有可能更新完之后 有方块可以消除,然后继续消除,知道 没有方块可以消除为止
    */
}

bool check(){
    for(int i=1;i<=5;i++)
        if(map[i][1])return 0;
    return 1;
}
void dfs(int x){
    if(check()){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=3;j++){
                printf("%d ",ans[i][j]);
            }
        printf("\n");
    }
    exit(0);
    }
    if(x==n+1)return;//要搜索到n 也就是第n步,因为前面有判断有没有全部消除
    cp(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+1][j]!=map[i][j]){//右移 右边可以为空 也可以为其他数
                    move(i,j,1);
                    ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=1;
                    dfs(x+1);
                    for(int qiq=1;qiq<=5;qiq++)
                        for(int qjq=1;qjq<=7;qjq++)
                            map[qiq][qjq]=cf[x][qiq][qjq];
                    /*ans[x][1]=-1;ans[x][2]=-1;ans[x][3]=-1;//似乎可以不用*/
                    
                    /*
                    移动 标记 更新 然后继续 下一步 移动 标记 更新  如果return 了 就开始回复 到移动之前
                    */
                }
                if(i-1>=1&&!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 qaq=1;qaq<=5;qaq++)
                        for(int qwq=1;qwq<=7;qwq++)
                            map[qaq][qwq]=cf[x][qaq][qwq];
                }
                /*
                    因为 左右移动都可以 移动到空白位置 然后下降,但是 如果 左移或者右移 左右有数,则会重复 ,所以留一个右移就好了            
                */
                
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=5;i++){
        for(int j=1;j<=8;j++){
            scanf("%d",&js);
            if(js==0)break;
            map[i][j]=js;
        }
    }
    dfs(1);
    printf("-1");
    return 0;
}