hdu3567 八數碼2(康託展開+多次bfs+預處理)

Eight II

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 130000/65536 K (Java/Others)
Total Submission(s): 4103    Accepted Submission(s): 878


Problem Description
Eight-puzzle, which is also called "Nine grids", comes from an old game. 

In this game, you are given a 3 by 3 board and 8 tiles. The tiles are numbered from 1 to 8 and each covers a grid. As you see, there is a blank grid which can be represented as an 'X'. Tiles in grids having a common edge with the blank grid can be moved into that blank grid. This operation leads to an exchange of 'X' with one tile.

We use the symbol 'r' to represent exchanging 'X' with the tile on its right side, and 'l' for the left side, 'u' for the one above it, 'd' for the one below it.



A state of the board can be represented by a string S using the rule showed below.



The problem is to operate an operation list of 'r', 'u', 'l', 'd' to turn the state of the board from state A to state B. You are required to find the result which meets the following constrains:
1. It is of minimum length among all possible solutions.
2. It is the lexicographically smallest one of all solutions of minimum length.
 

Input
The first line is T (T <= 200), which means the number of test cases of this problem.

The input of each test case consists of two lines with state A occupying the first line and state B on the second line.
It is guaranteed that there is an available solution from state A to B.
 

Output
For each test case two lines are expected.

The first line is in the format of "Case x: d", in which x is the case number counted from one, d is the minimum length of operation list you need to turn A to B.
S is the operation list meeting the constraints and it should be showed on the second line.
 

Sample Input
2 12X453786 12345678X 564178X23 7568X4123
 

Sample Output
Case 1: 2 dd Case 2: 8 urrulldr

題目傳送門

題目很好理解,就是個華容道的遊戲,唯一要注意的就是要輸出最短路徑,長度相同時字典序要最小。

這道題和hdu1430方法一樣,只不過1430是一次bfs+康託展開保存所有狀態,而這個起點有九種,所以只要九次bfs就可以了,另外路徑不能直接暴力保存,我是用了ans[x][e]來表示起點爲x,走到康託值爲e的操作字符,再用一個pre[x][e]來表示這個操作的前一個的康託值。另外這道題卡時間卡了一個減枝,就是如果前一步是u,那這一步就不需要d了,其他方向也一樣,另外再贊一下這種把函數寫在結構體裏面的方法,真是太好用了!!

對了,還有由於每次輸入的起點不一樣,還有其他數字的位子也不一樣,所以要用一個p來保存x的位置,(bfs過程中也要用p來表示x到哪裏了,並且記得更新),然後用一個re[]數組來表示出了x以外的其他數字的對應關係,然後就可以了。

建議先做一下hdu1430,這是1430的題解。點擊打開鏈接

上代碼。

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<bitset>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
using namespace std;
#define INF 0x3f3f3f3f
#define CLR(x,y) memset(x,y,sizeof(x))
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
typedef pair<int,int> pii;
typedef long long LL;
const double PI=acos(-1.0);
const int N=362880+10;
int fact[10]= {1,1,2,6,24,120,720,5040,40320,362880};
struct node {
	char arr[10];
	int val;
	int p;
	string step;
	void contor() {
		val=0;
		for(int i=0; i<9; i++) {
			int t=0;
			for(int j=i+1; j<9; j++) {
				if(arr[j]<arr[i])t++;
			}
			val+=t*fact[9-i-1];
		}
		val++;
	}
	void change_d(int x) {
		char temp=arr[x];
		arr[x]=arr[x+3];
		arr[x+3]=temp;
		p=x+3;
		step+='d';
	}
	void change_l(int x) {
		p=x-1;
		char temp=arr[x];
		arr[x]=arr[x-1];
		arr[x-1]=temp;
		step+='l';
	}
	void change_r(int x) {
		p=x+1;
		char temp=arr[x];
		arr[x]=arr[x+1];
		arr[x+1]=temp;
		step+='r';
	}
	void change_u(int x) {
		p=x-3;
		char temp=arr[x];
		arr[x]=arr[x-3];
		arr[x-3]=temp;
		step+='u';
	}
	node() {}
	node(char *s) {
		int i,j;
		for(i = 0; i<strlen(s); i++) {
			arr[i] = s[i];
		}
	}
};
int vis[N];
int pre[9][N];
char ans[9][N];
char re[10];
node s,t;
void bfs(int x) {
	memset(pre[x],-1,sizeof(pre[x]));
	memset(vis,0,sizeof(vis));
	s.contor();
	s.p=x;
	queue<node>q;
	vis[s.val]=1;
	q.push(s);
	node now,v;
	while(!q.empty()) {
		now=q.front();
		q.pop();
		v=now;
		int e=v.val;
		int len=v.step.length();
		//d
		if(v.p<6&&ans[x][e]!='u') {
			v.change_d(v.p);
			v.contor();
			if(!vis[v.val]) {
				vis[v.val]=1;
				ans[x][v.val]='d';
				pre[x][v.val]=e;
				q.push(v);
			}
		}
		//l
		v=now;
		if(v.p!=0&&v.p!=3&&v.p!=6&&ans[x][e]!='r') {
			v.change_l(v.p);
			v.contor();
			if(!vis[v.val]) {
				vis[v.val]=1;
				ans[x][v.val]='l';
				pre[x][v.val]=e;
				q.push(v);
			}
		}
	
		//r
		v=now;
		if(v.p!=2&&v.p!=5&&v.p!=8&&ans[x][e]!='l') {
			v.change_r(v.p);
			v.contor();
			if(!vis[v.val]) {
				vis[v.val]=1;
				ans[x][v.val]='r';
				pre[x][v.val]=e;
				q.push(v);
			}
		}
		//u
		v=now;
		if(v.p>2&&ans[x][e]!='d') {
			v.change_u(v.p);
			v.contor();
			if(!vis[v.val]) {
				vis[v.val]=1;
				ans[x][v.val]='u';
				pre[x][v.val]=e;
				q.push(v);
			}
		}
}
}
int main() {
	s = node("X12345678");
	bfs(0);
	s = node("1X2345678");
	bfs(1);
	s = node("12X345678");
	bfs(2);
	s = node("123X45678");
	bfs(3);
	s = node("1234X5678");
	bfs(4);
	s = node("12345X678");
	bfs(5);
	s = node("123456X78");
	bfs(6);
	s = node("1234567X8");
	bfs(7);
	s = node("12345678X");
	bfs(8);
	char ss[10];
	int T;
	cin>>T;
	int cas=1;
	while(T--) {
	scanf("%s",ss);
	int p;
	for(int i=0,j=0; i<9; i++) {
			if(ss[i]=='X'){
			p=i;
			}else{
			re[ss[i]-'0']=++j;	//記住  是j 
			}			
		}
		scanf("%s",ss);
		for(int i=0; i<9; i++) {
			if(ss[i]!='X')
			t.arr[i]=re[ss[i]-'0'];
			else t.arr[i]='X';
		}
		t.contor();
		int sum=t.val;
		string aa;
		aa="";
		while(sum!=-1){
			aa+=ans[p][sum];
			sum=pre[p][sum];
		}
		printf("Case %d: %d\n",cas++,aa.size()-1);//爲什麼要-1呢?因爲第一種狀態是空字符,不是路徑 
		for(int i=aa.size()-2;i>=0;i--)
		printf("%c",aa[i]);
		printf("\n");
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章