您的位置:首页 > 其它

zoj 3814 Sawtooth Puzzle

2014-11-14 08:23 375 查看
题意:9张正方形卡片摆成3*3,每张卡片有图案,求从当前状态旋转到目标状态的最短步。卡片的某些边类似齿轮,如果相邻的边都是齿轮边,它们就会同时旋转。

思路:搜索。这个题比较复杂,涉及到好多问题,比如状态的编码解码,图像相同的校验,旋转的模拟等等。首先编码问题用9位4进制数表示,我因为编码解码写错WA了好多发。。图像相同的校验暴力解决,注意可能出现对称的情况,即多个相同态。旋转的模拟用dfs(bfs超时),搜索哪些卡片会被带动,根据与原卡片的曼哈顿距离的奇偶性确定旋转方向。

程序的主体当然是BFS,因为需要求最短步,里面套一下上述功能就可以了。

#include<iostream>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<string.h>
#include<cstdio>

using namespace std;

#define INF 100000000

char G[10][10][10];
char G2[10][10][10];
bool st[10][4];

int match[10][4];	//哪些状态可看作终态 
int dis[266666];	//存每个状态与初态距离 

//判断是否为终态 
bool judge(int s){
	for(int t=8;t>=0;t--){
		int cur=s%4;
		s/=4;
		if(!match[t][cur])return 0;
	}
	return 1;
}

bool r[9];
int s[9];
bool dfs(int cur){
	if(cur>2){//上
		if(!r[cur-3])if(st[cur][(5-s[cur])%4]&&st[cur-3][(3-s[cur-3])%4]){
			r[cur-3]=1;
			dfs(cur-3);
		}
	}
	if(cur<6){//下 
		if(!r[cur+3])if(st[cur][(3-s[cur])%4]&&st[cur+3][(5-s[cur+3])%4]){
			r[cur+3]=1;
			dfs(cur+3);
		}
	}
	if(cur%3!=0){//左 
		if(!r[cur-1])if(st[cur][(4-s[cur])%4]&&st[cur-1][(6-s[cur-1])%4]){
			r[cur-1]=1;
			dfs(cur-1);
		}
	}
	if(cur%3!=2){//右 
		if(!r[cur+1])if(st[cur][(6-s[cur])%4]&&st[cur+1][(4-s[cur+1])%4]){
			r[cur+1]=1;
			dfs(cur+1);
		}
	}
}

//旋转函数,返回旋转后状态 
int rota(int x,int t){
	memset(r,0,sizeof(r));
	
	int tmp=x;
	for(int i=8;i>=0;i--){
		s[i]=tmp%4;
		tmp/=4;
	}
	r[t]=1;
	dfs(t);
	
	int re=0;
	for(int i=0;i<9;i++){
		if(!r[i])continue;
		if(abs(t-i)&1){
			s[i]+=3;
		}else{
			s[i]++;
		}
		s[i]%=4;
	}
	for(int i=0;i<9;i++){
		re*=4;
		re+=s[i];
	}
	return re;
}

int main(){
	int t;
	cin>>t;
	while(t--){
		//init
		memset(dis,0,sizeof(dis));
		memset(match,0,sizeof(match));
		//input
		for(int i=0;i<3;i++){
			for(int k=0;k<8;k++){
				for(int j=0;j<3;j++){
					scanf("%s",G[i*3+j][k]);
				}
			}
		}
		
		for(int i=0;i<3;i++){
			for(int k=0;k<8;k++){
				for(int j=0;j<3;j++){
					scanf("%s",G2[i*3+j][k]);
				}
			}
		}
		//
		for(int i=0;i<9;i++){
			for(int j=0;j<4;j++){
				scanf("%d",&st[i][j]);
			}
		}
		//
		bool ok;
		bool hasans=1;
		int ans=INF;
		for(int k=0;k<9;k++){
			//0
			ok=1;
			for(int i=0;i<8;i++){
				for(int j=0;j<8;j++){
					if(G[k][i][j]!=G2[k][i][j])ok=0;
				}
			}
			if(ok)match[k][0]=1;
			//90
			ok=1;
			for(int i=0;i<8;i++){
				for(int j=0;j<8;j++){
					if(G[k][7-j][i]!=G2[k][i][j])ok=0;
				}
			}
			if(ok)match[k][1]=1;
			//180
			ok=1;
			for(int i=0;i<8;i++){
				for(int j=0;j<8;j++){
					if(G[k][7-i][7-j]!=G2[k][i][j])ok=0;
				}
			}
			if(ok)match[k][2]=1;
			//270
			ok=1;
			for(int i=0;i<8;i++){
				for(int j=0;j<8;j++){
					if(G[k][j][7-i]!=G2[k][i][j])ok=0;
				}
			}
			if(ok)match[k][3]=1;
			
			if(match[k][0]+match[k][1]+match[k][2]+match[k][3]==0){
				hasans=0;break;
			}
		}
		if(!hasans){
			cout<<-1<<endl;
			continue;
		}
		
		queue<int> que; que.push(0); dis[0]=1;
		if(judge(0)){
			cout<<0<<endl;
			continue;
		}
		while(!que.empty()){
			int cur=que.front(); que.pop();
			for(int i=0;i<9;i++){
				int news=rota(cur,i);
				if(!dis[news]){
					dis[news]=dis[cur]+1;
					if(judge(news)){
						ans=dis[cur];
						break;
					}
					que.push(news);
				}
			}
			if(ans!=INF)break;
		}
		
		if(ans==INF){
			cout<<-1<<endl;
		}else{
			cout<<ans<<endl;
		}
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: