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;
}


發佈了137 篇原創文章 · 獲贊 28 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章