当前位置:首页 > NOIP真题代码注释 > 正文

2011提高组-玛雅游戏

#inclue<bits/stdc++.h>
#define ll long long
#define N 10

//快速读 
int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int n,map[N][N],ans[N][5],last[N][N][N],xiao[N][N];
//map表示整个输入 
//ans表示移动

//last[d][i][j]:第d步时在i行j列的原状态
void copy(int x){
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
        last[x][i][j]=map[i][j];
}

//掉下去 x统计map[i][j]下面几个0 
void update(){
    for(int i=1;i<=5;i++){
        int x=0;
        for(int j=1;j<=7;j++){
            if(!map[i][j])x++;
            else{
                map[i][j-x]=map[i][j];
                map[i][j]=0;
            }
        }
    }
}
//消掉
bool remove(){
    int flag=0;
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++){
        	//同列3个 
            if(i-1>=1&&i+1<=5&&map[i][j]==map[i-1][j]&&map[i][j]==map[i+1][j]&&map[i][j]){
                xiao[i-1][j]=1;xiao[i+1][j]=1;xiao[i][j]=1;flag=1;
            }
            //同行3个 
            if(j-1>=1&&j+1<=7&&map[i][j]==map[i][j+1]&&map[i][j]==map[i][j-1]&&map[i][j]){
                xiao[i][j]=1;xiao[i][j+1]=1;xiao[i][j-1]=1;flag=1;
            }
        }
    //没有可以消除的,返回 
    if(!flag)return 0;
    //处理需要消除的,归0 
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++)
        if(xiao[i][j]){
            xiao[i][j]=0; //归0 
            map[i][j]=0;  //消除 
        } 
    return 1;
} 

//检查判断第一行5列是否都为0,
//因为最后都掉下来了,所以就看第一行是否都消除了 
bool check(){
    for(int i=1;i<=5;i++)
        if(map[i][1])return 0;
    return 1;
}
//处理一次操作,向左 -1 或向右移动 +1 
//交换两个位置的方块,移动后要update,和remove 
void move(int i,int j,int x){
    int tmp=map[i][j];        
    map[i][j]=map[i+x][j];
    map[i+x][j]=tmp;
    update(); //移动后看是否掉落 
    while(remove())update();//掉落后,看能否消除,消除后看是否掉落 
}
 
void dfs(int x){
	//如果已经全部消除,则输出结果 
    if(check()){
        for(int i=1;i<=n;i++){
            if(i!=1)printf("\n");
            for(int j=1;j<=3;j++)
            printf("%d ",ans[i][j]);
        }
        exit(0);
    }
    //超过n步,则剪枝 
    if(x==n+1)return;
    //记录下第x步的原图状态 
    copy(x);
    for(int i=1;i<=5;i++)
        for(int j=1;j<=7;j++){
            if(map[i][j]){
            	//向右移动 
                if(i+1<=5&&map[i][j]!=map[i+1][j]){
                move(i,j,1);
                //ans记录下操作,i-1,j-1是因为题目下标从0开始的, 
                ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=1;
                //继续试操作 
                dfs(x+1);
                for(int i=1;i<=5;i++)
                    for(int j=1;j<=7;j++)
                    map[i][j]=last[x][i][j];//恢复上一次操作时原图 
                ans[x][1]=-1;ans[x][2]=-1;ans[x][3]=-1;
            }
            //想左移动 ,左边是0的情况才左移,算是一种剪枝-- 
			//上面右移包含了左边不是0的情况了。 
            if(i-1>=1&&map[i-1][j]==0){
                move(i,j,-1);
                //记录下i-1,j-1想左移动 
                ans[x][1]=i-1;ans[x][2]=j-1;ans[x][3]=-1;
                //下一步操作 
                dfs(x+1);
                for(int i=1;i<=5;i++)
                    for(int j=1;j<=7;j++)
                    map[i][j]=last[x][i][j];//恢复原状态 
                ans[x][1]=-1;ans[x][2]=-1;ans[x][3]=-1;
            }
            }
        }
} 
 
int main()
{
	//读入n,表示要求游戏通关的步数 
    n=read();
    //每两个整数之间用一个空格隔开,
	//每行以一个00 结束,自下向上表示每竖列方块的颜色编号
	//先列后行 
    for(int i=1;i<=5;i++){
        for(int j=1;j<=8;j++){
            int x=read();
            if(x==0)break;
            map[i][j]=x;
        }
    }
    //输出n行,每行包含3个整数x,y,g表示一次移动 
    memset(ans,-1,sizeof(ans));
    //从第一个开始搜搜 
    dfs(1);
    //没有答案,则输出-1 
    puts("-1");
    return 0;
}


更新时间 2019-07-24

有话要说...