【搜索】[NOIP2012]mayan游戏

题目自己上网找。
分析,由于只有五层,而且每一层的选择很多,所以总的状态十分多,果断dfs。
暴搜过70%数据。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,a[6][6][9],ans[6][3],dir[2]={-1,1};
bool f[6][6][9];
bool clear(int i){
    int j,k;
    bool flag=0;
    for(j=1;j<=5;j++)
        for(k=1;a[i][j][k];k++){
            if(a[i][j][k]==a[i][j][k-1]&&a[i][j][k]==a[i][j][k+1])
                f[i][j][k]=f[i][j][k-1]=f[i][j][k+1]=1,flag=1;
            if(a[i][j][k]==a[i][j-1][k]&&a[i][j+1][k]==a[i][j][k])
                f[i][j][k]=f[i][j-1][k]=f[i][j+1][k]=1,flag=1;
        }
    for(j=1;j<=5;j++)
        for(k=1;a[i][j][k];k++)
            if(f[i][j][k])
                a[i][j][k]=0,f[i][j][k]=0;
    return flag;
}
bool drop(int i){
    int j,k,l;
    bool flag=0;
    for(j=1;j<=5;j++){
        for(k=7;!a[i][j][k];k--);
        for(;k>0;k--)
            if(!a[i][j][k]){
                for(flag=1,l=k+1;a[i][j][l];l++)
                    a[i][j][l-1]=a[i][j][l];
                a[i][j][l-1]=a[i][j][l];
            }
    }
    return flag;
}
bool check(){
    for(int i=1;i<=5;i++)
        if(a[n][i][1])
            return 0;
    return 1;
}
void print(){
    for(int i=1;i<=n;i++)
        printf("%d %d %d\n",ans[i][0]-1,ans[i][1]-1,ans[i][2]);
}
void dfs(int i){
    if(i>n){
        if(check()){
            print();
            exit(0);
        }
        return;
    }
    int j,k,d,tj;
    for(j=1;j<=5;j++)
        for(k=1;a[i-1][j][k];k++)
            for(d=0;d<2;d++){
                memcpy(a[i],a[i-1],sizeof a[i]);
                tj=j+dir[d];
                if(!tj||tj>5)
                    continue;
                swap(a[i][j][k],a[i][tj][k]);
                ans[i][0]=j,ans[i][1]=k,ans[i][2]=dir[d];
                while(drop(i)||clear(i));
                dfs(i+1);
            }
}
int main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=5;i++)
        for(j=1;;j++){
            scanf("%d",&a[0][i][j]);
            if(!a[0][i][j])
                break;
        }
    dfs(1);
    puts("-1");
}

加上一个小小的剪枝,就AC了
如果相邻的两个格子都不是空的,我们只考虑向右移动。
如果左边的格子是空的,再考虑向左移动。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,a[6][6][9],ans[6][3];
bool f[6][6][9];
bool clear(int i){
    int j,k;
    bool flag=0;
    for(j=1;j<=5;j++)
        for(k=1;a[i][j][k];k++){
            if(a[i][j][k]==a[i][j][k-1]&&a[i][j][k]==a[i][j][k+1])
                f[i][j][k]=f[i][j][k-1]=f[i][j][k+1]=1,flag=1;
            if(a[i][j][k]==a[i][j-1][k]&&a[i][j+1][k]==a[i][j][k])
                f[i][j][k]=f[i][j-1][k]=f[i][j+1][k]=1,flag=1;
        }
    for(j=1;j<=5;j++)
        for(k=1;a[i][j][k];k++)
            if(f[i][j][k])
                a[i][j][k]=0,f[i][j][k]=0;
    return flag;
}
bool drop(int i){
    int j,k,l;
    bool flag=0;
    for(j=1;j<=5;j++){
        for(k=7;!a[i][j][k];k--);
        for(;k>0;k--)
            if(!a[i][j][k]){
                for(flag=1,l=k+1;a[i][j][l];l++)
                    a[i][j][l-1]=a[i][j][l];
                a[i][j][l-1]=a[i][j][l];
            }
    }
    return flag;
}
bool check(){
    for(int i=1;i<=5;i++)
        if(a[n][i][1])
            return 0;
    return 1;
}
void print(){
    for(int i=1;i<=n;i++)
        printf("%d %d %d\n",ans[i][0]-1,ans[i][1]-1,ans[i][2]);
}
void dfs(int i){
    if(i>n){
        if(check()){
            print();
            exit(0);
        }
        return;
    }
    int j,k,tj;
    for(j=1;j<=5;j++)
        for(k=1;a[i-1][j][k];k++){
            memcpy(a[i],a[i-1],sizeof a[i]);
            tj=j+1;
            if(tj<=5){
                swap(a[i][j][k],a[i][tj][k]);
                ans[i][0]=j,ans[i][1]=k,ans[i][2]=1;
                while(drop(i)||clear(i));
                dfs(i+1);
            }
            memcpy(a[i],a[i-1],sizeof a[i]);
            tj=j-1;
            if(tj&&!a[i][tj][k]){
                ans[i][0]=j,ans[i][1]=k,ans[i][2]=-1;
                swap(a[i][j][k],a[i][tj][k]);
                while(drop(i)||clear(i));
                dfs(i+1);
            }
        }
}
int main()
{
    int i,j;
    scanf("%d",&n);
    for(i=1;i<=5;i++)
        for(j=1;;j++){
            scanf("%d",&a[0][i][j]);
            if(!a[0][i][j])
                break;
        }
    dfs(1);
    puts("-1");
}

你可能感兴趣的:(C++,搜索,noip)