sicily 2011. Nine Digits(宽搜+康托展开) 解题报告
Description
Nine tiles, each with a number from 1 to 9 on it, are packed into a 3 by 3 frame. Your task is to arrange the tiles so that they are ordered as:
1 2 3
4 5 6
7 8 9
At each step, you can do the following operation to the tiles: Choose 2 by 2 tiles, rotate the tiles in clockwise order. For example:
1 2 3 4 1 3 1 2 3 1 2 3
4 5 6 => 5 2 6 or 4 5 6 => 4 8 5
7 8 9 7 8 9 7 8 9 7 9 6
Write a program to find the minimum number of steps.
Input
Input contains multiple test cases.
Each test case is a description of a configuration of the nine tiles. The description is just a list of the tiles in their initial positions, with the rows listed from top to bottom, and from left to right within a row, where the tiles are represented by numbers 1 to 9. For example:
9 8 7
6 5 4
3 2 1
is described by this list:
9 8 7 6 5 4 3 2 1
Output
Output the minimum number of steps on a single line for each test case.
Sample Input
1 2 3 4 5 6 7 8 9
4 1 3 5 2 6 7 8 9
4 1 3 5 2 6 7 8 9
Sample Output
0
3
0
3
解题报告:
刚看题目,我马上想到使用宽搜,先把所有情况搜出来,也就是9的阶乘362880种情况。但是由于不能够建立一个九位数的数组来保存这些数据,因此需要使用到康托展开。
康托展开的使用范围是对于n个数的排列进行状态的压缩和存储,例如要对9的全排列进行判重.没有必要开一个10的9次幂的数组,因此它有362880中情况。因此其思想就是相当于一个哈希函数。一个排列它所对应的位置就是它排的是第几大。比如321,对应的值就是6,因为前面有个123,132,213,231,312比它小。具体的计算方法见下面代码。C++代码见下面附加代码中的函数cantor()。
fumction ktzk(s:zrr):longint;
var i,time,j:longint;
begin
for i:= 1 to 12 do
begin
time:=0;
for j:= i+1 to 12 do
if (s[j]>s[i]) then inc(time);
inc(ktzk,mi[12-i]*tot);
end;
end;
var i,time,j:longint;
begin
for i:= 1 to 12 do
begin
time:=0;
for j:= i+1 to 12 do
if (s[j]>s[i]) then inc(time);
inc(ktzk,mi[12-i]*tot);
end;
end;
做完康托展开之后,就要实现四种情况的变换,这个也比较简单,使用四个函数来实现即可,但是写的过程需要特别小心。我这里出了错也是卡了很久。
需要注意的是这道题目测试数据较多,刚开始我使用cin,cout结果超时了,排了n久的错,终于想起要把输入输出换为c的。
下面是代码:
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
const int MAX=362882;
int s[9]={1,10,100,1000,10000,100000,1000000,10000000,100000000};
int jie[9]={0,1,2,6,24,120,720,5040,40320};
int visit[MAX];
int len[MAX];
int four[4];
int lu(int num)
{
int result;
result=num%s[4];
result+=((num/s[5])%10)*s[4];
result+=num/s[8]*s[5];
result+=((num/s[6])%10)*s[6];
result+=((num/s[4])%10)*s[7];
result+=((num/s[7])%10)*s[8];
return result;
}
int ru( int num )
{
int result = num/s[5]*s[5];
result += num/s[1]%10;
result += num/s[4]%10*s[1];
result += num/s[2]%10*s[2];
result += num%10*s[3];
result += num/s[3]%10*s[4];
return result;
}
int ld( int num )
{
int result = num/s[6]*s[6] + num%10;
result += num/s[2]%10*s[1];
result += num/s[5]%10*s[2];
result += num/s[3]%10*s[3];
result += num/s[1]%10*s[4];
result += num/s[4]%10*s[5];
return result;
}
int rd( int num )
{
int result = num % s[3] + num/s[8]*s[8];
result += num/s[4]%10*s[3];
result += num/s[7]%10*s[4];
result += num/s[5]%10*s[5];
result += num/s[3]%10*s[6];
result += num/s[6]%10*s[7];
return result;
}
int cantor(int key)
{
int result,temp[9];
for(int i=8;i>=0;i--)
{
temp[i]=key%10;
key=key/10;
}
result=0;
for(int i=0;i<8;i++)
{
int tot=0;
for(int j=i+1;j<9;j++)
if(temp[j]<temp[i])
tot++;
result+=tot*jie[8-i];
}
return result;
}
int key2[4];
int start=123456789;
queue<int>que;
int main()
{
int temp;
int key1;
len[0]=0;
que.push(start);
visit[0]=1;
while(!que.empty())
{
temp=que.front();
que.pop();
key1=cantor(temp);
four[0]=lu(temp);
four[1]=ru(temp);
four[2]=ld(temp);
four[3]=rd(temp);
for(int i=0;i<4;i++)
{
key2[i]=cantor(four[i]);
if(!visit[key2[i]])
{
visit[key2[i]]=1;
que.push(four[i]);
len[key2[i]]=len[key1]+1;
}
}
}
int input[9];
while(scanf("%d",&input[0])!=EOF)
{
temp=input[0];
for(int i=1;i<9;i++)
{
scanf("%d",&input[i]);
temp=input[i]+temp*10;
}
printf("%d\n",len[cantor(temp)]);
}
return 0;
}