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
",cas++,aa.size()-1);//为什么要-1呢?因为第一种状态是空字符,不是路径 
		for(int i=aa.size()-2;i>=0;i--)
		printf("%c",aa[i]);
		printf("
");
	}
}



原文地址:https://www.cnblogs.com/mountaink/p/9536727.html