1.康托展开,八数码在交换的过程中状态会改变,康托展开用于求出某一格局的状态数。
2.逆序数,通过求初始格局和目标格局逆序数,然后在比较两者的逆序数的奇偶性是否相同,如果奇偶性相同,则可以从初始格局变到目标格局。否则,不可达。逆序数求法:假设有n个元素的排列,a[i]为排列中的元素(0<=i
3.在八数码中0位置的数与它相邻的上下左右的位置的数交换不会影响这个格局的逆序数的奇偶性。比如有以下格局:
4 |
6 |
7 |
5 |
8 |
1 |
2 |
3 |
0 |
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define N 9
int jc[N+1]={1,1,2,6,24,120,720,5040,40320,362880};//0-9的阶乘
typedef struct data
{
int arr[N];//格局
int hash;//存储某一格局的哈希
int pos;//0当前位置
int step;//记录步数
}Node;
int dir[4][2]={
{0,1},
{1,0},
{0,-1},
{-1,0}
};
/**
* 康托展开
*/
int cantor(int arr[N])
{
int i,j;
int sum=0;
for( i=0;iarr[j])
nmin++;
}
sum+=(nmin*jc[N-i-1]);
}
return sum;
}
/**
*数据交换
*/
void swap(int *arr,int i,int j)
{
int t=arr[i];
arr[i]=arr[j];
arr[j]=t;
}
/**
* 打印数组,测试用
*/
void printArray(int * arr)
{
int i,j;
for (i=0;i q;
set setHash;
Node now,next;
copyArray(arr,now.arr);
int pos=0;
for (i=0;i=0&&offsetX<3&&offsetY<3&&offsetY>=0)
{
copyArray(now.arr,next.arr);//每次换方向,就复制
next.step=now.step;
next.step++;
swap(next.arr,now.pos,offsetY*3+offsetX);
next.hash=cantor(next.arr);
next.pos=(offsetY*3+offsetX);
int begin=setHash.size();
setHash.insert(next.hash);
int end=setHash.size();
if(next.hash==tHash){
return next.step;
}
if(end>begin)
{
q.push(next);
}
}
}
}
return -1;
}
/**
*求逆序数
*/
int inversion(int arr[N])
{
int sum=0;
for(int i=0;i='0'&&s.at(i)<='8')
{
is[i]=s.at(i)-'0';
}else
{
is[i]=0;
}
if (t.at(i)>='0'&&t.at(i)<='8')
{
it[i]=t.at(i)-'0';
}else
{
it[i]=0;
}
}
int sHash,tHash;//源哈希和目标哈希
sHash=cantor(is);
tHash=cantor(it);
int inver1=inversion(is);//求初始格局的逆序数
int inver2=inversion(it);//求目标格局的逆序数
if((inver1+inver2)%2==0)
{
int step=bfs(is,sHash,tHash);
cout<