简单的BFS处理——八数码问题

八数码是一道极为经典的宽搜题目,在此题目如下:

3×3九宫棋盘,放置数码为1-8的8个棋牌,剩下一个空格,只能通过棋牌向空格的移动来改变棋盘的布局。要求:根据给定初始布局,问:至少移动几次才能从初始布局到达目标布局。

目标布局如下图:

Image


Input Description

3行,每行3个0-8的不重复整数,其中0表示空格所在的位置,数字间用空格隔开,表示初始布局,数据保证该初始布局一定能移到目标布局。

Output Description

一个整数,表示最少移动到目标布局的次数。

Sample

INPUT 

0 7 6
8 4 3
5 2 1

OUTPUT 

4





对于每种情况,可以看作9个数字的不同排列,也就是说会有9!=362880种情况,而每种情况我用一个字符串进行记录,也方便调用字符串函数减少工作量。为了避免搜索重复情况,将建立一个HASH表。每种排列的康拓展开是唯一,故可以此作为对应关系。


康拓展开,即得到该排列在全部排列中的大小排名,具体公式是:X=a[n]*(n-1)!+……+a[1]*0! 其中a[n]为其后比该位数字小的数的个数,即逆序数。


具体代码实现如下:

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

char aim[10]="876543210";
char step[400000][10];
int hash[400000];

int cantor(char x[],int n)
{
	int fac[]={1,1,2,6,24,120,720,5040,40320};
	int i,j,num=0,count;
	for(i=0;i<n;i++)
	{
		count=0;
		for(j=i+1;j<n;j++)
			if(x[j]<x[i]) count++;
		
		num+=count*fac[n-1-i];
	}
	return num+1;
}

int makestep(int p,int q,int n)
{
	int i,j=q+1,t,num;
	char newstep[10];
	
	for(i=p;i<=q;i++)
	{
		if(strcmp(step[i],aim)==0)
		{
			printf("%d",n);
			return 0;
		}
		
		t=0;
		while(step[i][t]!='0') t++;
		
		
		if(t>2)
		{
			strcpy(newstep,step[i]);
			newstep[t]=step[i][t-3];
			newstep[t-3]=step[i][t];
			num=cantor(newstep,9);
			if(hash[num])
			{
				strcpy(step[j],newstep);
				hash[num]=0;
				j++;
			}
		} 
		
		if(t<6)
		{
			strcpy(newstep,step[i]);
			newstep[t]=step[i][t+3];
			newstep[t+3]=step[i][t];
			num=cantor(newstep,9);
			if(hash[num])
			{
				strcpy(step[j],newstep);
				hash[num]=0;
				j++;
			}
		}
		
		if(t%3!=0)
		{
			strcpy(newstep,step[i]);
			newstep[t]=step[i][t-1];
			newstep[t-1]=step[i][t];
			num=cantor(newstep,9);
			if(hash[num])
			{
				strcpy(step[j],newstep);
				hash[num]=0;
				j++;
			}
		}
		
		if(t%3!=2)
		{
			strcpy(newstep,step[i]);
			newstep[t]=step[i][t+1];
			newstep[t+1]=step[i][t];
			num=cantor(newstep,9);
			if(hash[num])
			{
				strcpy(step[j],newstep);
				hash[num]=0;
				j++;
			}
		}
	}
	
	makestep(q+1,j-1,n+1);
	
	return 0;
}

int main()
{
	int i,trans;
	for(i=0;i<9;i++)
	{
		scanf("%d",&trans);
		step[0][i]=trans+'0';
	}
	step[0][9]='\0';
	for(i=0;i<400000;i++) hash[i]=1;
	hash[cantor(step[0],9)]=0;
	
	makestep(0,0,0);
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值