1 solutions

  • 0
    @ 2025-2-28 11:43:50

    搜索,剪枝 O((nm)5)O((nm)^5)

    由于最多枚举 5步,数据范围很小,因此直接暴搜即可。

    搜索顺序:依次枚举每一步选择哪个方块,向左右哪个方向移动。

    剪枝情况有三种:

    向右移动时,如果右侧的方块颜色和当前方块颜色相同,则剪枝。这是由于交换之后状态没有任何变化。,由于题目中要求步数恰好是 n 的方案,因此这个无意义的操作可能被用来填补操作步数,因此不能被剪掉。

    向左移动时,如果左侧有方块,则直接减掉。这是由于输出的答案要求字典序最小,如果左侧有方块,那么将左侧的方块向右移动的字典序小于将当前方块向左移动的字典序。

    当某种颜色的方块数量大于0小于等于2时,一定无解,直接剪枝。

    代码实现

    #include<bits/stdc++.h>
    using namespace std;
    int n;
    int g[5][7],bg[5][5][7]; //地图和每步的地图备份
    int cnt[11],bcnt[5][11]; //颜色个数和每步的颜色备份
    bool st[5][7]; //标记当前地图是否需要消除
    struct Path{ //路径
        int x,y,d;
    }path[5];
    bool remove()
    {
    	bool has_changed=false;
    	memset(st,0,sizeof st); //清空标记
        for(int x=0;x<5;x++)
        {
            for(int y=0;y<7;y++)
            {
                if(g[x][y]) //当前是颜色
                {
                    int l=x,r=x; //找到左右端点并标记
                    while(l-1>=0&&g[l-1][y]==g[x][y]) l--;
                    while(r+1<5&&g[r+1][y]==g[x][y]) r++;
                    if(r-l+1>=3)
                    {
                        st[x][y]=true;
                        has_changed=true;
                    }
                    int d=y,u=y; //找到上下端点并标记
                    while(d-1>=0&&g[x][d-1]==g[x][y]) d--;
                    while(u+1<7&&g[x][u+1]==g[x][y]) u++;
                    if(u-d+1>=3)
                    {
                        st[x][y]=true;
                        has_changed=true;
                    }
                }
            }
        }
        for(int x=0;x<5;x++)
        {
            for(int y=0;y<7;y++)
            {
                if(st[x][y])
                {
                    cnt[g[x][y]]--,cnt[0]--; //对应颜色减少,个数减少
                    g[x][y]=0; //地图状态清空
                }
            }
        }
        return has_changed;
    }
    void move(int a,int b,int c)
    {
        swap(g[a][b],g[c][b]); //第b行的第a列和c列进行交换
      	do
        {
            for(int x=0;x<5;x++) //从左往右枚举列
            {
                int z=0; //表示落下的列
                for(int y=0;y<7;y++) //枚举每列
                {
                    if(g[x][y]) //存在
                    {
                        g[x][z++]=g[x][y];
                    }
                }
                while(z<7) g[x][z++]=0; //补充完成
            }
        }while(remove());
    }
    bool dfs(int u)
    {
        if(u==n) return !cnt[0]; //步数搜索完成,判断是否成功
        for(int i=1;i<=10;i++) //枚举每种颜色,剪枝
        {
            if(cnt[i]==1||cnt[i]==2)
            {
                return false;
            }
        }
        memcpy(bg[u],g,sizeof g); //第u层开始地图的状态
        memcpy(bcnt[u],cnt,sizeof cnt); //第u层开始的颜色的状态
        for(int x=0;x<5;x++)
        {
            for(int y=0;y<7;y++)
            {
                if(g[x][y]) //当前格子有颜色 
                {
                    int z=x+1; //右边
                    if(z<5)
                    {
                        path[u]={x,y,1};
                        move(x,y,z); //移动
                        if(dfs(u+1)) return true;
                        //当钱路走不通,回到初始状态,再换个方向走
                        memcpy(g,bg[u],sizeof g); 
                        memcpy(cnt,bcnt[u],sizeof cnt);
                    }
                    z=x-1;
                    if(z>=0&&!g[z][y]) //可以往左边走,且左边是空的
                    {
                        path[u]={x,y,-1};
                        move(x,y,z);
                        if(dfs(u+1)) return true;
                        memcpy(g,bg[u],sizeof g);
                        memcpy(cnt,bcnt[u],sizeof cnt);
                    }
                }
            }
        }
        return false;
    }
    int main()
    {
        cin>>n;
        for(int x=0;x<5;x++)
        {
            int y=0,c;
            while(cin>>c,c) //获取第x列的元素
            {
                g[x][y++]=c;
                cnt[c]++,cnt[0]++;
            }
        }
        if(dfs(0))
        {
            for(int i=0;i<n;i++)
            {
                cout<<path[i].x<<" "<<path[i].y<<" "<<path[i].d<<endl;
            }
        }
        else
        {
            cout<<-1;
        }
        return 0;
    }
    
    • 1

    Information

    ID
    1090
    Time
    1000ms
    Memory
    256MiB
    Difficulty
    10
    Tags
    # Submissions
    1
    Accepted
    1
    Uploaded By