题目链接:http://wikioi.com/problem/1225/
算法与思路:康托展开(hash)+ bfs;
这个题目的的搜索部分对于很多同学来说并不难,关键在于棋盘状态的储存;
如果直接使用0~8组成的9位数作为数组下标,要开到8亿显然不现实,
这个时候就要用到康托展开了;
初次接触的同学请戳链接 康托展开-维基百科,上面讲的很详细。
然后就是相对简单的bfs了,详见注释。
#include<stdio.h>
char st[9] = {0};
struct node
{
int val; //康托值
int step; //步数
}map[400000];
int vis[400000];
int factor[] = {1,1,2,6,24,120,720,5040,40320,362880};//阶乘
void swap(char *a, char *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int cantor(char x[]) //康托展开
{
int sum = 0, s;
for(int i = 0; i < 9; i++)
{
s = 0;
for(int j = i + 1; j < 9; j++)
if(x[j] < x[i])
s++;
sum += s * factor[9 - i - 1];
}
return sum;
}
void trans(int x) //康托展开逆运算
{
int visit[10] = {0};
int t;
for(int i = 0; i < 9; i++)
{
t = x / factor[9 - i - 1];
x %= factor[9 - i - 1];
for(int j = 0; j <= t; j++)
if(visit[j] == 1)
t++;
visit[t] = 1;
st[i] = t;
}
}
int main()
{
int zero; //0的位置
int aim = 46685; //目标状态康托值
int head = 0, tail = 1; //首尾指针
for(int i = 0; i < 9; i++)
{
scanf("%c", &st[i]);
st[i] -= '0';
}
map[0].val = cantor(st); //纪录初始状态的康托值
vis[map[0].val] = 1; //标记此状态,以便判重
while(head < tail)
{
if(aim == map[head].val) //找到目标状态就结束
break;
trans(map[head].val);
for(int i = 0; i < 9; i++) //寻找当前状态0的位置
if(st[i] == 0)
{
zero = i;
break;
}
if(zero + 3 <= 8) //向下
{
swap(&st[zero], &st[zero+3]); //交换0与下方数字位置
map[tail].val = cantor(st); //求出交换后的康托值
if(vis[map[tail].val] == 0)
{
vis[map[tail].val] = 1;
map[tail].step = map[head].step + 1; //记录步数
tail++;
}
swap(&st[zero], &st[zero+3]);
}
if(zero - 3 >= 0) //向上
{
swap(&st[zero], &st[zero-3]);
map[tail].val = cantor(st);
if(vis[map[tail].val] == 0)
{
vis[map[tail].val] = 1;
map[tail].step = map[head].step + 1;
tail++;
}
swap(&st[zero], &st[zero-3]);
}
if(zero + 1 >= 0 && zero % 3 != 2)//判断向右是否合法
{
swap(&st[zero], &st[zero+1]);
map[tail].val = cantor(st);
if(vis[map[tail].val] == 0)
{
vis[map[tail].val] = 1;
map[tail].step = map[head].step+1;
tail++;
}
swap(&st[zero], &st[zero+1]);
}
if(zero - 1 >= 0 && zero % 3 != 0)//判断向左是否合法
{
swap(&st[zero], &st[zero-1]);
map[tail].val = cantor(st);
if(vis[map[tail].val] == 0)
{
vis[map[tail].val] = 1;
map[tail].step = map[head].step + 1;
tail++;
}
swap(&st[zero], &st[zero-1]);
}
head++;
}
printf("%d\n", map[head].step);
return 0;
}