闲谈:写搜索真的心累,复杂复杂.代码又长,又难调.幸好蓝书搜索并不是很短,且y总大部分都做了视频,且有辛格大佬不然我估计写不下去了.言归正传,讲讲这个题目怎么做.
题目是你可以移动且只能移动n次,使得屏幕的方块全部消掉.移动就是左移和右移,然后假如你移动方向有方块你就交换.没有方块就就掉落呗.然后消了之后也会掉落,一旦相同连续颜色的方块>=3就可以消了.答案优先级是按照x为第一关健字,y为第二关健字,1优先于-1,1表示向右移动,-1表示向左移动.
做法就是模拟上面描述的过程,搜索的剪枝有2个.
1.一旦有种方块数量<3.那么直接return false就可以了.
2.由于向右移动的优先级大于向左移动的优先级,那么一旦一个方块左边有方块且它想向左移动,是不是就等于它左边的方块向右移动呢?换句话来说,向左移动时,左边必定没有方块.
至于搜索顺序就是枚举x然后枚举y,先右移,再左移.然后我们为了方便数组,建立的是一幅倒图.
下面就是激动人心的代码时刻了.(什么时候才能到数论哎QAQ

#include <bits/stdc++.h>
using namespace std;
int n;
int an[6][8],ban[6][6][8];
bool st[6][8];
int cnt[15],bcnt[5][15];
struct node
{
    int x,y,w;
}path[5];
void move(int x,int y,int mx)//处理操作.
{
    swap(an[mx][y],an[x][y]);//交换.
    while(true)
    {
        bool flag=false;
        //删掉空位.
        for(int i=0;i<5;i++)
        {
            int z=0;
            for(int j=0;j<7;j++)
            {
                if(an[i][j])
                {
                    an[i][z++]=an[i][j];
                }
            }
            while(z<7) an[i][z++]=0;
        }
        //标记要删除的地方
        memset(st,false,sizeof st);
        for(int i=0;i<5;i++)//枚举所有点.
        {
            for(int j=0;j<7;j++)
            {
                if(an[i][j])
                {
                    int l,r;
                    l=r=i;
                    while(l-1>=0&&an[l][j]==an[l-1][j]) l--;
                    while(r+1<5&&an[r][j]==an[r+1][j]) r++;
                    if(r-l+1>=3) {flag=true;st[i][j]=true;}
                    else
                    {
                        l=r=j;
                        while(l-1>=0&&an[i][l]==an[i][l-1]) l--;
                        while(r+1<7&&an[i][r]==an[i][r+1]) r++;
                        if(r-l+1>=3) {flag=true;st[i][j]=true;}
                    }
                }
            }
        }
        //删除标记的地方.
        if(flag)
        {
            for(int i=0;i<5;i++)
            {
                for(int j=0;j<7;j++)
                {
                    if(st[i][j])
                    {
                        cnt[0]--;
                        cnt[an[i][j]]--;
                        an[i][j]=0;
                    }
                }
            }
        }
        else break;
    }
}

bool dfs(int u)//处理枚举.
{
    if(u==n)//假如我已经操作了n次,那么判断下是不是屏幕清0了.
    {
        return (!cnt[0]);
    }
    for(int i=1;i<=10;i++) 
    {
        if(cnt[i]==1||cnt[i]==2) return false;
    }//剪枝1.
    memcpy(ban[u],an,sizeof ban[u]);
    memcpy(bcnt[u],cnt,sizeof cnt);
    for(int x=0;x<5;x++)//先枚举x坐标
    {
        for(int y=0;y<7;y++)//再枚举y坐标
        {
            if(an[x][y])//能移动的前提是这个位子上有方块.
            {
                int mx=x+1;//向右移动.
                if(mx<5)//只有<5就可以交换
                {
                    move(x,y,mx);
                    path[u]={x,y,1};
                    if(dfs(u+1)) return true;
                    memcpy(an,ban[u],sizeof ban[u]);
                    memcpy(cnt,bcnt[u],sizeof cnt);
                }
                mx=x-1;//向左移动.
                if(mx>=0&&!an[mx][y])
                {
                    move(x,y,mx);
                    path[u]={x,y,-1};
                    if(dfs(u+1)) return true;
                    memcpy(an,ban[u],sizeof ban[u]);
                    memcpy(cnt,bcnt[u],sizeof cnt);
                }
            }
        }
    }
    return false;//假如都不成功就返回false
}

int main()//处理输入输出
{
    cin>>n;
    for(int i=0;i<5;i++)
    {
        int t=0,x;
        while(cin>>x,x) {an[i][t++]=x;cnt[0]++;cnt[x]++;}
    }//处理输入
    if(dfs(0))
    {
        for(int i=0;i<n;i++) cout<<path[i].x<<' '<<path[i].y<<' '<<path[i].w<<endl;
    }
    else puts("-1");
    return 0;
}