USACO Training Section 3.2 Magic Squares


英文原题  中文题译

大意:有人发明了一种有8个块三种变换方式的平面魔方,给定初始和目标状态,要求求出最少需要的变换的数量并给出具体的变换方式。

每个状态是1-8的一个全排列,状态空间为8!,可以用康托展开得到排列的字典序列数,从而用8!的状态空间来存储访问标记和跟踪标记。

我在这里用了另一种方式,每个状态用8×3=24位表示(3位表示0-7),可放在一个整数内。注意到这7个数的位置就可以确定8个数的全排列,因而1<<21个标记可以顺序的表示所有状态,每个标记为U/A/B/C分别表示未访问、从变换A/B/C得到,需2位,从而1<<18个整数的数组可以表示整个状态空间。用宽度优先搜索得到目标状态之后根据所记录的变换做逆变换,直到得到原始状态位置,并递归的输出所需的解。

/*
ID: blackco3
TASK: msquare
LANG: C++
*/
#include <iostream>
using namespace std;
#define _max_state_ 40320
#define _vis_mask_ 0x
char vis[1<<21] ;
int source, target, queue[_max_state_] ;
int trans[3][8]={ {7, 6, 5, 4, 3, 2, 1, 0}, {3, 0, 1, 2, 5, 6, 7, 4}, {0, 6, 1, 3, 4, 2, 5, 7} } ;

void get_trace( int state, int level ) {
	if( state == source ){
		cout << level << endl ;
		return ;
	}
	int pre=0 ;
	for( int j=0; j<8; j++ )
		pre |= ( ( state >> (j*3) ) & 0x7 ) << ( 3*trans[ vis[state>>3]-'A' ][j] ) ;
	get_trace( pre, level+1 );
	cout << vis[state>>3] ;
}

int main() {
	freopen("msquare.in", "r", stdin);
	freopen("msquare.out", "w", stdout);
	for( int i=0, val=0 ; i<8; i++ ){
		cin >> val ;
		source |= i<<(3*i),  target |= (--val)<<(3*i) ;
	}
	int *head=queue, *tail=queue ;
	*(tail++) = source, vis[source>>3]='A' ;
	do {
		register int cur= *(head++) ;
		if( cur==target ) {
			get_trace( target, 0 );
			cout << endl ;
			return 0 ;
		}
		for( int i=0; i<3; i++ ){
			register int next=0 ;
			for( int j=0; j<8; j++ )
				next |= ( ( cur >> (trans[i][j]*3) ) & 0x7 ) << (3*j) ;
			if( vis[next>>3] )
				continue ;
			vis[next>>3] = 'A' + i, *(tail++) = next ;
		}
	} while ( head != tail );
	return 0;
}

你可能感兴趣的:(J#,asp)