您的位置:首页 > 其它

wikioi1225 八数码难题

2013-07-29 18:55 183 查看

题目描述 Description

Yours和zero在研究A*启发式算法.拿到一道经典的A*问题,但是他们不会做,请你帮他们.

问题描述

在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入描述 Input Description

输入初试状态,一行九个数字,空格用0表示

输出描述 Output Description

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数(测试数据中无特殊无法到达目标状态数据)

样例输入 Sample Input

283104765

样例输出 Sample Output

4

初始状态经过一步生成新的状态,这些状态又经过一步生成新的状态,就这样生成下去,总会找到目标状态,而且是最少次数的,因为我们每一次都会把X步能走的的找完,没有就查看X+1步的。这就是BFS。

当一个状态1生成状态2之后,状态2又可能生成状态1,状态1又生成状态2,产生了死循环,所以需要判重,我用了康托展开。

#include <stdio.h>
#include <string.h>

const int B[4]={-3,-1,1,3};

struct node
{
int s_t[10];		//当前状态
long ans;			//当前步数
}d[555555];				//队列

char s[10];
bool Hash[400000]={0};	//Hash
int e_t[10]={0,1,2,3,8,0,4,7,6,5},tmp[10]; //目标状态,临时变量

long Jst(int n) 		//求阶乘
{
if(n==0)	return 0;
long jst=1;
for(int i=1;i<=n;i++)
jst*=i;
return jst;
}

long Kto(int s[])		//康拓展开
{
long hs=0;int co=0;
bool h[9]={0};
for(int i=1;i<=8;i++)
{
co=0;
for(int k=s[i]-1;k>=0;k--)
if(!h[k])	co++; //它前面的有几个比它小?
h[s[i]]=1;
hs+=(co*Jst(9-i));
}
return hs+1; 		//康拓展开的规则,最后一定要加1
}

bool Flag(int a,int b)
{
if((a==1 && b==-1) || (a==1 && b==-3))	return 0;
if((a==2 && b==-3))	return 0;
if((a==3 && b==1) || (a==3 && b==-3))	return 0;
if((a==4 && b==-1))	return 0;
if((a==6 && b==1))	return 0;
if((a==7 && b==3) ||(a==7 && b==-1))	return 0;
if((a==8 && b==3))	return 0;
if((a==9 && b==1) || (a==9 && b==3))	return 0;
return 1;
}

int main()
{
int count=0;
scanf("%s",s);
for(int i=0;i<9;i++)
{
d[1].s_t[i+1]=s[i]-'0';
tmp[i+1]=s[i]-'0';
}
d[1].ans=0;
Hash[Kto(tmp)]=1;
long head=1,tail=1; 		//队列初始化
int b;bool flag;
while(head<=tail)
{
for(int i=1;i<=9;i++)	tmp[i]=d[head].s_t[i];//取队首
for(int i=0;i<=3;i++)
{
for(int j=1;j<=9;j++)
if(tmp[j]==0)
{
b=j;
break;
}				//找0的位置
if(!Flag(b,B[i]))	continue; 	//是否越界
int t=tmp[b];tmp[b]=tmp[b+B[i]];tmp[b+B[i]]=t; //移动
flag=0;
for(int j=1;j<=9;j++)
if(tmp[j]!=e_t[j])
{
flag=1;
break;
} 				//判断是否到达目标状态
if(!flag)	break;
long hs=Kto(tmp);
if(Hash[hs]==0) 	//判重
{
Hash[hs]=1;
tail++;
for(int j=1;j<=9;j++)
d[tail].s_t[j]=tmp[j]; //入队
d[tail].ans=d[head].ans+1; //是谁生成了它,便在它的步数上加1作为自己的步数
}
t=tmp[b];tmp[b]=tmp[b+B[i]];tmp[b+B[i]]=t; //换回来供他人使用
}
head++;
if(!flag)	break;
}
printf("%ld\n",d[head].ans+1);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: