• [NOIP2011提高组]Mayan游戏


    题目:洛谷P1312、Vijos P1738、codevs1136。

    题目大意:在一个7行5列的棋盘(左下角坐标0,0)上,有一些不同颜色的棋子。

    规定某一时刻,连续三个横排或竖列的棋子颜色相同,则它们被消掉(同时满足条件的一起消掉,存在多个这样的情况有公共棋子时,所有的都消掉)。

    然后有一种操作:

    将一个棋子往左/右移动或和左边/右边的棋子交换。(左为-1,右为1)

    规定棋盘上没有棋子时,游戏胜利。

    现在给出顺时针旋转$90^circ$后的棋盘,你要进行恰好n次操作,使游戏胜利,输出字典序最小(横坐标最小,然后纵坐标最小,然后方向最小,1比-1小)的操作方案。

    如果不可能,输出-1。

    解题思路:看到这么小的数据范围($nleq 5$),肯定想到暴搜,而好像也没有别的方法。

    题目要求字典序最小,那我们就按字典序最小的方案搜,找到就输出结束程序。

    这里有一些剪枝:

    ①当一种颜色的个数为1或2时,一定不可能胜利,跳出。

    ②搜的时候,先搜往右的,如果当前棋子和右边棋子颜色相同,就不搜。

    ③搜左边时,只考虑左边为空的情况,如果不为空,则等价于左边的棋子向右交换的操作,字典序更小,因此一定不可能为答案。

    消除的情况,可以枚举中间点,然后判断三个是否相同即可。

    掉下来的情况,暴力移动即可。

    剩下的,只需注意状态的保存和还原就行了。

    别的没什么技巧可言。

    C++ Code:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    int n;
    int bl[9][9],tong[12]={0},ansx[7],ansy[7],yd[7];
    bool bj[9][9];
    void clean(){
    	bool hasqc=true;
    	while(hasqc){
    		hasqc=false;
    		bool dxl=true;
    		while(dxl){
    			dxl=false;
    			for(int i=0;i<5;++i)
    			for(int j=0;j<8;++j)
    			if(bl[i][j]==0&&bl[i][j+1])
    			bl[i][j]=bl[i][j+1],bl[i][j+1]=0,dxl=true;
    		}
    		memset(bj,0,sizeof bj);
    		for(int i=0;i<5;++i)
    		for(int j=0;j<8;++j){
    			if(i&&i<4&&bl[i][j]&&bl[i][j]==bl[i-1][j]&&bl[i][j]==bl[i+1][j])
    				bj[i][j]=bj[i-1][j]=bj[i+1][j]=hasqc=true;
    			if(j&&bl[i][j]&&bl[i][j]==bl[i][j-1]&&bl[i][j]==bl[i][j+1])
    			bj[i][j]=bj[i][j-1]=bj[i][j+1]=hasqc=true;
    		}
    		if(hasqc){
    			for(int i=0;i<5;++i)
    			for(int j=0;j<8;++j)
    			if(bj[i][j])--tong[bl[i][j]],bl[i][j]=0;
    		}
    	}
    }
    void dfs(int now){
    	if(now>n){
    		for(int i=0;i<12;++i)
    		if(tong[i])return;
    		for(int i=1;i<=n;++i)
    		printf("%d %d %d
    ",ansx[i],ansy[i],yd[i]);
    		exit(0);
    	}
    	for(int i=0;i<12;++i)
    	if(tong[i]&&tong[i]<3)return;
    	int ylzt[9][9],yltong[12];
    	for(int i=0;i<9;++i)for(int j=0;j<9;++j)
    	ylzt[i][j]=bl[i][j];
    	memcpy(yltong,tong,sizeof tong);
    	for(int i=0;i<5;++i){
    		for(int j=0;j<8;++j)
    		if(ylzt[i][j]){
    			if(i<4&&ylzt[i+1][j]!=ylzt[i][j]){
    				memcpy(tong,yltong,sizeof tong);
    				for(int i=0;i<9;++i)for(int j=0;j<9;++j)
    				bl[i][j]=ylzt[i][j];
    				int x=bl[i][j];
    				bl[i][j]=bl[i+1][j];
    				bl[i+1][j]=x;
    				ansx[now]=i,ansy[now]=j,yd[now]=1;
    				clean();
    				dfs(now+1);
    			}
    			if(i&&!ylzt[i-1][j]){
    				memcpy(tong,yltong,sizeof tong);
    				for(int i=0;i<9;++i)for(int j=0;j<9;++j)
    				bl[i][j]=ylzt[i][j];
    				bl[i-1][j]=bl[i][j];
    				bl[i][j]=0;
    				ansx[now]=i,ansy[now]=j,yd[now]=-1;
    				clean();
    				dfs(now+1);
    			}
    		}
    	}
    	for(int i=0;i<9;++i)for(int j=0;j<9;++j)
    	bl[i][j]=ylzt[i][j];
    	memcpy(tong,yltong,sizeof tong);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=0;i<5;++i){
    		int t;
    		scanf("%d",&t);
    		for(int j=0;t;++j){
    			bl[i][j]=t;
    			++tong[t];
    			scanf("%d",&t);
    		}
    	}
    	dfs(1);
    	puts("-1");
    	return 0;
    }
  • 相关阅读:
    hdu 2066 一个人的旅行
    hdu 3790 最短路径问题(迪杰斯特拉)
    hdu 2544 最短路
    hdu 1548 A strange lift(迪杰斯特拉,邻接表)
    hdu 1035 Robot Motion
    hdu 1032 The 3n + 1 problem
    hdu 1031 Design T-Shirt
    hdu 1030 Delta-wave
    hdu1231(最大连续子序列)
    hdu1423(最长公共递增子序列)
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8044515.html
Copyright © 2020-2023  润新知