HDU-1043 Eight

这道题刚开始单纯的用BFS做,从初始状态搜到12345678x,因为有很多组输入,妥妥的TLE
后来试了下双向BFS,还是TLE,(没做好优化,优化好的话是可以卡时间过去的)
最好最简单的解法是,从12345678x开始搜索,打表记录路径和移动,这样搜索一次,就把能到达的状态还有路径全部记录下来了,再输入时直接查询输出就可以,很快
状态压缩的话需要用一种编码方式,将012345678的全排列对应为0~362880之间的数,具体操作看代码
#include
#include
#include
#include
#include
#include
using namespace std;
const int dm[]={-3,3,-1,1};
const char mop[]={'u','d','l','r'}; //这里的移动是与dm对应的 
const char mop0[]={'d','u','r','l'}; //这里是反向的移动,用来保存打表 
const int ten[]={1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1};
bool vis[362880]; //访问标记 
int f[362880]; //保存父节点 
char op[362880]; //保存移动 
int move(int n,int i) //移动 
{
	int pos=9,tmp=n;
	while(pos>1)
	{
		if(n%10==0) break;
		n/=10;
		pos--;
	}
	if(pos%3==1&&i==2) return -1;
	if(pos%3==0&&i==3) return -1;
	if(pos<4&&i==0) return -1;
	if(pos>6&&i==1) return -1;
	int np=pos+dm[i];
	int t=tmp%ten[np-1]/ten[np];
	tmp+=ten[pos]*t;
	tmp-=ten[np]*t;
	return tmp;
}
int fact[9]; //编码用 
void init() //初始化 
{  
	fact[0]=1;  
	for(int i=1;i<9;i++) 
	fact[i]=fact[i-1]*i;
	memset(vis,false,sizeof(vis));
} 
int get_code(int s) //转码 
{
	int code=0;
	int st[9];
	for(int i=8;i>=0;i--,s/=10) 
	st[i]=s%10; 
	for(int i=0;i<9;i++)
	{    
		int cnt=0;    
		for(int j=i+1;j<9;j++) 
		if(st[j] q;
	q.push(sta0);
	insert(get_code(sta0));
	memset(f,-1,sizeof(f));
	while(!q.empty()) //从初始状态开始BFS,打表 
	{
		int u=q.front();//cout<<1<<" "< s0;
		if(vis[code]) //被访问过,可以到达 
		{
			while(f[code]!=-1) //寻找父节点,输出移动操作 
			{
				printf("%c",op[code]);
				code=f[code];
			}
		}
		else printf("unsolvable");
		printf("\n");
	}
	return 0;
}

你可能感兴趣的:(HDU-1043 Eight)