码迷,mamicode.com
首页 > 其他好文 > 详细

[NOIP2011提高组]Mayan游戏

时间:2017-12-15 19:31:31      阅读:127      评论:0      收藏:0      [点我收藏+]

标签:题目   strong   ems   pre   判断   暴搜   main   for   因此   

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

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

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

然后有一种操作:

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

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

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

如果不可能,输出-1。

解题思路:看到这么小的数据范围($n\leq 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\n",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;
}

[NOIP2011提高组]Mayan游戏

标签:题目   strong   ems   pre   判断   暴搜   main   for   因此   

原文地址:http://www.cnblogs.com/Mrsrz/p/8044515.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!