USACO Training Section 3.2 Magic Squares

[url="http://ace.delos.com/usacoprob2?a=KxExhYBcUZv&S=msquare"]英文原题[/url] [url="http://www.wzoi.org/usaco/main.asp?dir=14&wenjian=407"]中文题译[/url]

大意:有人发明了一种有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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值