• [luogu P1312]Mayan游戏


    其实就是一道锻炼码力的简单题……

    看到题目中的(0<xleqslant 5)也就知道是爆搜了吧(

    我们仿照写游戏的方法多写几个函数,能够有效降低错误率(确信

    我们写出大致的搜索流程来:

    如果当前步数大于(n)直接返回;
    如果当前已经为终态,直接输出答案;
    否则枚举每种可能情况继续搜。

    没错就是这么暴力

    接下来讲具体实现。

    首先我们对全局变量和数组进行一下约定:

    int n;//见题目
    int board[10][10];//棋盘
    int step[10][10];//存储步数
    int mem[10][10][10];//鉴于搜索下一步的时候我们会不可避免地更改原数组,我们需要保存一下当前的状态
    bool del[10][10];//见remove函数部分
    

    一开始的读入非常简单:读到0换行即可

    scanf("%d",&n);
    for(int i=1;i<=5;i++)
    {
        int cnt=0;
        while(1)
        {
            int xx;scanf("%d",&xx);
            if(xx==0)break;
            board[i][++cnt]=xx;
        }
    }
    

    我们需要对题目的一些操作进行一下模拟。

    首先是fall函数:它让悬空的块下落。
    可以发现,我们用一个变量来存下移的最终位置,就可以简单地进行实现。

    void fall()
    {
        int cnt;
        for(int i=1;i<=5;i++)
        {
            cnt=0;
            for(int j=1;j<=7;j++)
            {
                if(board[i][j]==0)cnt++;
                else
                {
                    if(cnt==0)continue;
                    board[i][j-cnt]=board[i][j];
                    board[i][j]=0;
                }
            }
        }
    }
    

    然后是三消remove函数:
    我们分别暴力判断横向和纵向每一次可以消掉哪些块,全都用del数组给标记出来,最后一起消掉。
    别忘了最后要将del数组清零,消完之后fall一次让可能悬空的块下坠。
    当然就像样例一样,一次消除是:消除当前->下坠->出现新的可三消块->再次消除当前……
    于是我们将这个函数修改一下,让它发现本次有消除操作就返回1,没有就返回0。
    于是我们可以这样调用remove函数:

    while(remove());
    

    简单粗暴(

    remove函数实现:

    bool remove()
    {
        bool flag=0;
        for(int i=1;i<=5;i++)
            for(int j=2;j<=6;j++)
                if(board[i][j]!=0&&board[i][j]==board[i][j-1]&&board[i][j]==board[i][j+1])
                {
                    flag=1;
                    del[i][j]=del[i][j-1]=del[i][j+1]=1;
                }
        for(int i=2;i<=4;i++)
            for(int j=1;j<=7;j++)
                if(board[i][j]!=0&&board[i][j]==board[i-1][j]&&board[i][j]==board[i+1][j])
                {
                    flag=1;
                    del[i][j]=del[i-1][j]=del[i+1][j]=1;
                }
        if(!flag)return 0;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=7;j++)
                if(del[i][j])
                    board[i][j]=del[i][j]=0;
        fall();
        return 1;
    }
    

    接下来是移动块函数move和判断是否结束函数gameover。
    move函数只需要移动一次并调用fall坠落一次,然后remove即可。
    gameover直接全屏扫。

    void move(int xx,int yy,int dir)//用dir标记方向
    {
        swap(board[xx][yy],board[xx+dir][yy]);
        fall();while(remove());
    }
    bool gameover()
    {
        for(int i=1;i<=5;i++)
            if(board[i][1]!=0)
                return 0;
        return 1;
    }
    

    接下来是dfs函数的枚举部分。
    首先我们用mem储存一下;
    然后只需要分方向枚举,枚举到一种情况就记录步数继续搜;
    回溯的时候撤销所记录的步数,用mem数组换回原来的状态即可。
    一个小剪枝:在交换之前判断一下,避免将相同的块交换即可。

    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
            mem[xx][i][j]=board[i][j];
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
            if(board[i][j]!=0)
            {
                if(i<=4&&board[i][j]!=board[i+1][j])
                {
                    move(i,j,1);
                    step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=1;
                    dfs(xx+1);
                    step[xx][1]=step[xx][2]=step[xx][3]=-1;
                    for(int i=1;i<=5;i++)
                        for(int j=1;j<=7;j++)
                            board[i][j]=mem[xx][i][j];
                }
                if(i>=2&&board[i][j]!=board[i-1][j])
                {
                    move(i,j,-1);
                    step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=-1;
                    dfs(xx+1);
                    step[xx][1]=step[xx][2]=step[xx][3]=-1;
                    for(int i=1;i<=5;i++)
                        for(int j=1;j<=7;j++)
                            board[i][j]=mem[xx][i][j];
                }
            }
    

    于是我们就这么水完了一道蓝题

    完整代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    int n,board[10][10],step[10][10],mem[10][10][10];
    bool del[10][10];
    void fall()
    {
        int cnt;
        for(int i=1;i<=5;i++)
        {
            cnt=0;
            for(int j=1;j<=7;j++)
            {
                if(board[i][j]==0)cnt++;
                else
                {
                    if(cnt==0)continue;
                    board[i][j-cnt]=board[i][j];
                    board[i][j]=0;
                }
            }
        }
    }
    bool remove()
    {
        bool flag=0;
        for(int i=1;i<=5;i++)
            for(int j=2;j<=6;j++)
                if(board[i][j]!=0&&board[i][j]==board[i][j-1]&&board[i][j]==board[i][j+1])
                {
                    flag=1;
                    del[i][j]=del[i][j-1]=del[i][j+1]=1;
                }
        for(int i=2;i<=4;i++)
            for(int j=1;j<=7;j++)
                if(board[i][j]!=0&&board[i][j]==board[i-1][j]&&board[i][j]==board[i+1][j])
                {
                    flag=1;
                    del[i][j]=del[i-1][j]=del[i+1][j]=1;
                }
        if(!flag)return 0;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=7;j++)
                if(del[i][j])
                    board[i][j]=del[i][j]=0;
        fall();
        return 1;
    }
    void move(int xx,int yy,int dir)
    {
        swap(board[xx][yy],board[xx+dir][yy]);
        fall();while(remove());
    }
    bool gameover()
    {
        for(int i=1;i<=5;i++)
            if(board[i][1]!=0)
                return 0;
        return 1;
    }
    void dfs(int xx)
    {
        if(gameover())
        {
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=3;j++)printf("%d ",step[i][j]);
                printf("
    ");
            }
            exit(0);
        }
        if(xx>n)return;
        for(int i=1;i<=5;i++)
            for(int j=1;j<=7;j++)
                mem[xx][i][j]=board[i][j];
        for(int i=1;i<=5;i++)
            for(int j=1;j<=7;j++)
                if(board[i][j]!=0)
                {
                    if(i<=4&&board[i][j]!=board[i+1][j])
                    {
                        move(i,j,1);
                        step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=1;
                        dfs(xx+1);
                        step[xx][1]=step[xx][2]=step[xx][3]=-1;
                        for(int i=1;i<=5;i++)
                            for(int j=1;j<=7;j++)
                                board[i][j]=mem[xx][i][j];
                    }
                    if(i>=2&&board[i][j]!=board[i-1][j])
                    {
                        move(i,j,-1);
                        step[xx][1]=i-1;step[xx][2]=j-1;step[xx][3]=-1;
                        dfs(xx+1);
                        step[xx][1]=step[xx][2]=step[xx][3]=-1;
                        for(int i=1;i<=5;i++)
                            for(int j=1;j<=7;j++)
                                board[i][j]=mem[xx][i][j];
                    }
                }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=5;i++)
        {
            int cnt=0;
            while(1)
            {
                int xx;scanf("%d",&xx);
                if(xx==0)break;
                board[i][++cnt]=xx;
            }
        }
        dfs(1);
        printf("-1
    ");
        return 0;
    }
    

    最慢的点跑了1.09s,但还是够AC了(笑

  • 相关阅读:
    Screen print or copy
    <转>关于SQL Server数据库的若干注意事项
    sql server 链接到oracle库,读取对应信息
    LinkedServer链接服务器的使用
    序号生成一例
    新解:报表服务器数据库的版本格式无效,或无法读取。已找到的版本为“Unknown”,而所需的版本为“C.0.8.40”。
    GridView to Excel
    sql server临时表是否存在
    <转>SQL Server大表转为分区表实例
    <转> 人生十二个经典领悟
  • 原文地址:https://www.cnblogs.com/pjykk/p/14170354.html
Copyright © 2020-2023  润新知