• 【Luogu】P1312Mayan游戏(暴搜)


      题目链接

      由于是暴搜题,所以这篇博客只讲怎么优化剪枝,以及一些细节。

      模拟消除思路:因为消除可以拆分成小的横条或竖条,而这些条的长度至少为三,所以一块可消除的区域至少会有一个中心点。这里的中心点可以不在正中间,只需要不是条上的第一个或者最后一个。

      于是枚举中间点,搜索它为中心最多向四个方向能扩展多远。如果搜索出来的横向满足长度要求,或竖向满足长度要求,就给他们打上一个标记。

      注意,这里只是打上标记,不能直接清零,很可能另一个方块的结算还得用到这个方块。

      等到枚举所有的中间点并给所有可消除的方块打上标记之后,可以把所有标记上的方块清空。然后检查有没有地方可以落下去。

      注意所有方块落下去之后还有可能接着消消乐,所以在落完之后还要再循环回去检查有没有可消除的方块。这里使用一个递归的代码来实现。

      

    int count(int x){
        bool vis[8][6],flag=0;
        int cnt=0;
        memset(vis,0,sizeof(vis));
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j){
                int col=Map[x][i][j];
                if(!col)    continue;
                int u=i,d=i,l=j,r=j;
                while(u>1&&Map[x][u-1][j]==col)    u--;
                while(d<n&&Map[x][d+1][j]==col)    d++;
                while(l>1&&Map[x][i][l-1]==col)    l--;
                while(r<m&&Map[x][i][r+1]==col)    r++;
                if(d-u>=2)
                    for(int k=u;k<=d;++k)    vis[k][j]=1;
                if(r-l>=2)
                    for(int k=l;k<=r;++k)    vis[i][k]=1;
            }
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j)
                if(vis[i][j]){
                    Map[x][i][j]=0;    cnt++;
                }
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j)
                if(!Map[x][i][j]){
                    int s=i;
                    while(s<n&&!Map[x][s][j])    s++;
                    if(!Map[x][s][j])    continue;
                    flag=1;
                    Map[x][i][j]=Map[x][s][j];
                    Map[x][s][j]=0;
                }
        if(flag)    cnt+=count(x);
        return cnt;
    }

    注意最后倒数第三行。flag表示的是有没有方块落下,因为有落下方块就有新一轮消除的可能性,所以可以递归这个函数,直到没有任何方块落下为止。此时递归终止,开始回溯计算答案。  

      再说说剪枝的几个小技巧。

      1、优先考虑坐标字典序小的向右移动,这样一旦搜到答案就是字典序最小的解。

      2、只有当左边没有方块的时候才向左移动,否则右面方块向左移动等价于左面方块向右移动,而这个状态已经搜过了。

      3、不交换两个颜色相同的方块。这个没什么好说的。

      最后给出代码。

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cctype>
    #include<cstring>
    using namespace std;
    
    inline long long read(){
        long long num=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){
            if(ch=='-')    f=-1;
            ch=getchar();
        }
        while(isdigit(ch)){
            num=num*10+ch-'0';
            ch=getchar();
        }
        return num*f;
    }
    
    int num;
    int n=7,m=5;
    int Max;
    int Map[10][10][10];
    int posx[100],posy[100],move[100];
    
    inline void copy(int x){
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j)    Map[x+1][i][j]=Map[x][i][j];
    }
    
    int count(int x){
        bool vis[8][6],flag=0;
        int cnt=0;
        memset(vis,0,sizeof(vis));
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j){
                int col=Map[x][i][j];
                if(!col)    continue;
                int u=i,d=i,l=j,r=j;
                while(u>1&&Map[x][u-1][j]==col)    u--;
                while(d<n&&Map[x][d+1][j]==col)    d++;
                while(l>1&&Map[x][i][l-1]==col)    l--;
                while(r<m&&Map[x][i][r+1]==col)    r++;
                if(d-u>=2)
                    for(int k=u;k<=d;++k)    vis[k][j]=1;
                if(r-l>=2)
                    for(int k=l;k<=r;++k)    vis[i][k]=1;
            }
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j)
                if(vis[i][j]){
                    Map[x][i][j]=0;    cnt++;
                }
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j)
                if(!Map[x][i][j]){
                    int s=i;
                    while(s<n&&!Map[x][s][j])    s++;
                    if(!Map[x][s][j])    continue;
                    flag=1;
                    Map[x][i][j]=Map[x][s][j];
                    Map[x][s][j]=0;
                }
        if(flag)    cnt+=count(x);
        return cnt;
    }
                
    
    void dfs(int use,int deep){
        if(use!=0&&deep==Max)    return;
        if(use==0){
            if(deep==Max){
                for(int i=1;i<=Max;++i)    printf("%d %d %d
    ",posy[i]-1,posx[i]-1,move[i]);
                exit(0);
            }
            return;
        }
        copy(deep);
        for(register int j=1;j<=m;++j)
            for(register int i=1;i<=n;++i){
                if(!Map[deep][i][j])    continue;
                if(Map[deep][i][j]!=Map[deep][i][j+1]&&j<m){
                    int a=Map[deep][i][j],b=Map[deep][i][j+1];
                    Map[deep+1][i][j]=b;Map[deep+1][i][j+1]=a;
                    posx[deep+1]=i;    posy[deep+1]=j;    move[deep+1]=1;
                    int q=count(deep+1);
                    dfs(use-q,deep+1);
                    copy(deep);
                }
                if(!Map[deep][i][j-1]&&j>1){
                    int a=Map[deep][i][j],b=Map[deep][i][j-1];
                    Map[deep+1][i][j]=b;Map[deep+1][i][j-1]=a;
                    posx[deep+1]=i;    posy[deep+1]=j;    move[deep+1]=-1;
                    int s=i;
                    while(s>1&&Map[deep+1][s-1][j-1]==0){
                        Map[deep+1][s--][j-1]=0;
                        Map[deep+1][s][j-1]=a;
                    }
                    int q=count(deep+1);
                    dfs(use-q,deep+1);
                    copy(deep);
                }
            }
    }
    
    
    int main(){
        Max=read();
        int start=0;
        for(int i=1;i<=m;++i)
            for(int j=1;;j++){
                Map[0][j][i]=read();
                if(Map[0][j][i]==0)    break;
                start++;
            }
        dfs(start,0);
        printf("-1");
        return 0;
    }
  • 相关阅读:
    [FAQ] GitHub 开启二次验证之后,如何通过 https clone 项目 ?
    [FAQ] GoLand 需要手动开启代码补全吗 ?
    [FAQ] 夏玉米 按规则查询域名靠谱吗 ?
    [FAQ] Error: com.mysql.jdbc.Driver not loaded. :jdbc_driver_library
    [php-src] Php内核的有趣高频宏
    [php-src] Php扩展开发的琐碎注意点、细节
    [ELK] Docker 运行 Elastic Stack 支持 TLS 的两种简单方式
    [Contract] Solidity 生成随机数方案
    [MySQL] 导入数据库和表的两种方式
    [ELK] 生产环境中 Elasticsearch 的重要配置项
  • 原文地址:https://www.cnblogs.com/cellular-automaton/p/7637992.html
Copyright © 2020-2023  润新知