解题思路是宽搜+康托压缩。具体就是从123456789开始向外宽搜,找到所有情况并记录,然后对输入进行常数时间的查找,最后输出结果。另外,由于1到9的全排列有9!个,不加处理直接开数组的话,可以开10^9(10表示1-10这10个数,9表示有9个位)个,但是这样空间就很大。而利用康托压缩,根据全排列中每个数只会出现一次的实际情况,可以将数组大小从10^9压缩为9!个,也即是去除了重复出现某些数字(缺失某些数字)的排列情况,具体实现请参考代码。
另:简言之,康托压缩是通过判断当前排列在全排列中属于第几大排列而实现的。
Run Time: 0.67sec
Run Memory: 2120KB
Code length: 3177Bytes
SubmitTime: 2012-01-12 01:13:13
// Problem#: 2011
// Submission#: 1188530
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include <cstdio>
#include <queue>
using namespace std;
int factorial[ 9 ] = { 40320, 5040, 720, 120, 24, 6, 2, 1, 1 };
int tile[ 362880 ] = { };
void rotate1( int from[], int to[] );
void rotate2( int from[], int to[] );
void rotate3( int from[], int to[] );
void rotate4( int from[], int to[] );
void itoa( int n, int a[] ) {
for ( int i = 8; i >= 0; i-- ) {
a[ i ] = n % 10;
n /= 10;
}
}
int atoi( int a[] ) {
int n = 0;
for ( int i = 0; i < 9; i++ )
n = n * 10 + a[ i ];
return n;
}
int cantor( int a[] ) {
int i, j, count, n = 0;
for ( i = 0; i < 9; i++ ) {
count = 0;
for ( j = i + 1; j < 9; j++ ) {
if ( a[ i ] > a[ j ] )
count++;
}
n += count * factorial[ i ];
}
return n;
}
int main()
{
int i;
queue<int> q;
int n, size, step;
int temp[ 9 ], now[ 9 ];
step = 0;
q.push( 123456789 );
while ( !q.empty() ) {
size = q.size();
while ( size-- ) {
itoa( q.front(), now );
rotate1( now, temp );
n = cantor( temp );
if ( tile[ n ] == 0 ) {
tile[ n ] = step + 1;
q.push( atoi( temp ) );
}
rotate2( now, temp );
n = cantor( temp );
if ( tile[ n ] == 0 ) {
tile[ n ] = step + 1;
q.push( atoi( temp ) );
}
rotate3( now, temp );
n = cantor( temp );
if ( tile[ n ] == 0 ) {
tile[ n ] = step + 1;
q.push( atoi( temp ) );
}
rotate4( now, temp );
n = cantor( temp );
if ( tile[ n ] == 0 ) {
tile[ n ] = step + 1;
q.push( atoi( temp ) );
}
q.pop();
}
step++;
}
tile[ 0 ] = 0;
while ( scanf( "%d", &now[ 0 ] ) != EOF ) {
for ( i = 1; i < 9; i++ )
scanf( "%d", &now[ i ] );
printf( "%d\n", tile[ cantor( now ) ] );
}
return 0;
}
void rotate1( int from[], int to[] ) {
to[ 0 ] = from[ 1 ];
to[ 1 ] = from[ 4 ];
to[ 2 ] = from[ 2 ];
to[ 3 ] = from[ 0 ];
to[ 4 ] = from[ 3 ];
to[ 5 ] = from[ 5 ];
to[ 6 ] = from[ 6 ];
to[ 7 ] = from[ 7 ];
to[ 8 ] = from[ 8 ];
}
void rotate2( int from[], int to[] ) {
to[ 0 ] = from[ 0 ];
to[ 1 ] = from[ 2 ];
to[ 2 ] = from[ 5 ];
to[ 3 ] = from[ 3 ];
to[ 4 ] = from[ 1 ];
to[ 5 ] = from[ 4 ];
to[ 6 ] = from[ 6 ];
to[ 7 ] = from[ 7 ];
to[ 8 ] = from[ 8 ];
}
void rotate3( int from[], int to[] ) {
to[ 0 ] = from[ 0 ];
to[ 1 ] = from[ 1 ];
to[ 2 ] = from[ 2 ];
to[ 3 ] = from[ 4 ];
to[ 4 ] = from[ 7 ];
to[ 5 ] = from[ 5 ];
to[ 6 ] = from[ 3 ];
to[ 7 ] = from[ 6 ];
to[ 8 ] = from[ 8 ];
}
void rotate4( int from[], int to[] ) {
to[ 0 ] = from[ 0 ];
to[ 1 ] = from[ 1 ];
to[ 2 ] = from[ 2 ];
to[ 3 ] = from[ 3 ];
to[ 4 ] = from[ 5 ];
to[ 5 ] = from[ 8 ];
to[ 6 ] = from[ 6 ];
to[ 7 ] = from[ 4 ];
to[ 8 ] = from[ 7 ];
}
本文详细介绍了使用康托压缩和广度优先搜索算法解决排列问题的方法,通过从最小排列开始逐步扩展,高效地找到所有可能的排列,并通过常数时间查找优化了结果输出。
740

被折叠的 条评论
为什么被折叠?



