HDU 1043 Eight(反向BFS打表+康托展开)


原题链接:Here!

分析:求经过若干次四个操作 ' r ' , ' l ' , ' u ' , ' d ' 到状态1 2 3 4 5 6 7 8 x,输出操作顺序。因为最终状态一定,所以采用反向BFS打表,记录路径即可。

CODE:

/*
	Note:
		因为题目要求是任意状态求是否能到一个"完美状态",因为任意状态不确定性和完美状态的确定性,所以不妨
	反向BFS+打表
		抠脚 
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<queue>
using namespace std;
#define test

int fac[]={1,1,2,6,24,120,720,5040,40320,362880};
int Cantor(int *s,int n){		// 康托展开 
	int ans=0;
	for(int i=0;i<n;i++){
		int tmp=0;
		for(int j=i+1;j<n;j++)
			if(s[i]>s[j])	tmp++;
		ans += tmp*fac[n-1-i]; 
	}
	return ans;
}
void unCantor(int index,int *t,int n){	// 康托逆展开 
	index--;
	int i,j;
	int vis[10]={0};
	for(i=0;i<n;i++){
		int tmp=index/fac[n-1-i];
		for(j=0;j<=tmp;j++)		 
			if(vis[j])	tmp++;
		
		t[i]=tmp+1;
		vis[tmp]=1;
		index%=fac[n-1-i]; 
	}
}

const int maxn = 362880;	// 9! = 362880
bool can[maxn];				// 记录状态是否出现 
char ans[maxn][42];			// 打个表将答案打到一个二维数组中,第一维是Cantor值,然后是一个字符串 
int  target[]={1,2,3,4,5,6,7,8,0};		// 目标状态 
int  tt[9];
struct Node{		// Node的信息代表 key是空白点在(x,y)的状态下的康托值,tol是拓展层数 
	int key,x,y,tol;
	Node(int _key,int _x,int _y,int _tol):key(_key),x(_x),y(_y),tol(_tol){}
}; 
queue<Node> q;
void bfs(){
	// 初始化 
	memset(can,false,sizeof(can));
	while(!q.empty())	q.pop();
	
	int t_key=Cantor(target,9);		// 找到目标状态康托值
	can[t_key]=true;
	ans[t_key][0]='\0';
	q.push(Node(t_key,2,2,0));		// 3x3 初始点x在(2,2) 
	while(!q.empty()){
		Node tmp=q.front();	q.pop();
		unCantor(tmp.key+1,tt,9);	// 将Cantor值对应的状态录入到数组tt中 
		int x=tmp.x, y=tmp.y;
		// 接下来4个if 代表上下左右走,因为是倒序BFS所以向上走时就是原来的向下走,其他相同 
		if(x>=1){		// 倒序向上走 
			swap(tt[x*3+y],tt[(x-1)*3+y]);	 // 交换两个格子
			t_key=Cantor(tt,9);
			if(!can[t_key]){
				q.push(Node(t_key,x-1,y,tmp.tol+1));	// 记录向上走后的状态,然后tol+1 
				can[t_key]=true;
				for(int i=0;i<tmp.tol;i++)	ans[t_key][i]=ans[tmp.key][i]; 	// *继承父亲的路径 
				ans[t_key][tmp.tol]='d'; 
				ans[t_key][tmp.tol+1]='\0';
			} 
			swap(tt[x*3+y],tt[(x-1)*3+y]); 	// 为什么每次都要交换过来,如果不能交换,当然得保持原样 
		}
		if(y>=1){		// 倒序向左走 
			swap(tt[x*3+y],tt[x*3+(y-1)]);
			t_key=Cantor(tt,9);
			if(!can[t_key]){
				q.push(Node(t_key,x,y-1,tmp.tol+1));
				can[t_key]=true;
				for(int i=0;i<tmp.tol;i++)	ans[t_key][i]=ans[tmp.key][i];
				ans[t_key][tmp.tol]='r';
				ans[t_key][tmp.tol+1]='\0';
			}
			swap(tt[x*3+y],tt[x*3+(y-1)]);
		}
		if(x<=1){		// 倒序向下走 
			swap(tt[x*3+y],tt[(x+1)*3+y]);
			t_key=Cantor(tt,9);
			if(!can[t_key]){
				q.push(Node(t_key,x+1,y,tmp.tol+1));
				can[t_key]=true;
				for(int i=0;i<tmp.tol;i++)	ans[t_key][i]=ans[tmp.key][i];
				ans[t_key][tmp.tol]='u';
				ans[t_key][tmp.tol+1]='\0'; 
			}
			swap(tt[x*3+y],tt[(x+1)*3+y]);
		}
		if(y<=1){		// 倒序向右走 
			swap(tt[x*3+y],tt[x*3+(y+1)]);
			t_key=Cantor(tt,9);
			if(!can[t_key]){
				q.push(Node(t_key,x,y+1,tmp.tol+1));
				can[t_key]=true;
				for(int i=0;i<tmp.tol;i++)	ans[t_key][i]=ans[tmp.key][i]; 
				ans[t_key][tmp.tol]='l';
				ans[t_key][tmp.tol+1]='\0';
			}
			swap(tt[x*3+y],tt[x*3+(y+1)]);
		}
	} 
}

int d[9];						// 存放目标状态 
void solve(){
	int t_key=Cantor(d,9);
	if(!can[t_key]){ printf("unsolvable\n"); return; }
	int len=strlen(ans[t_key]);
	for(int i=len-1;i>=0;i--)
		printf("%c",ans[t_key][i]);
	printf("\n");
}

int main(){
	bfs();		// 反向BFS打表 
	#ifdef test
		freopen("Hdu 1043 Eight.txt","r",stdin);
	#endif
	string op;
	while(getline(cin,op)){
		for(int i=0,j=0;i<op.size();i++){
			if(op[i]>='1' && op[i]<='8')
				d[j++]=op[i]-'0';
			if(op[i]=='x')
				d[j++]=0;
		}
		solve();
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值