USACO 3.2 Magic Squares 【搜索+康托展开】

题目背景

在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有8个大小相同的格子的魔板:

1 2 3 4 
8 7 6 5

题目描述

我们知道魔板的每一个方格都有一种颜色。这8种颜色用前8个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。对于上图的魔板状态,我们用序列(1,2,3,4,5,6,7,8)来表示。这是基本状态。

这里提供三种基本操作,分别用大写字母“A”,“B”,“C”来表示(可以通过这些操作改变魔板的状态):

“A”:交换上下两行;

“B”:将最右边的一列插入最左边;

“C”:魔板中央四格作顺时针旋转。

下面是对基本状态进行操作的示范: 
A: 
1 2 3 4 ==> 8 7 6 5 
8 7 6 5 ==> 1 2 3 4

B: 
1 2 3 4 ==> 4 1 2 3 
8 7 6 5 ==> 5 7 6 5

C: 
1 2 3 4 ==> 1 7 2 4 
8 7 6 5 ==> 8 6 3 5

对于每种可能的状态,这三种基本操作都可以使用。

你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。

分析

这题应当就是搜索了,但是到底是深搜还是广搜呢?注意到题目中说是要“用最少的基本操作”,也就是要求最短路径,那么就一定是广搜啦。但一定记住要在每次搜索的时候判重,那么我们如何记录这八个方块的状态呢?显然是可以用一个八维数组的,但是还可以有一种更为普遍的方法,那就是康托展开: 
X=a[n](n-1)!+a[n-1](n-2)!+…+a[i]*(i-1)!+…+a[1]*0! 其中a[i]为当前未出现的元素中是排在第几个(从0开始)。 
没错,它其实就是另一种特殊的字符串哈希,本质是把一个字符串中每个字符的位置和信息结合在一起,从而确立一个字符串的唯一性。有了这个方法,我们就可以AC了。

下面是参考代码:

/*
ID: linda_f1
PROG: msquare
LANG: C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int fac[9]={1,1,2,6,24,120,720,5040,40320};//contor 
struct point
{
    int a[10];
    int n;
    int step;
}p[800000];
int goal,bas,tot=0;
int f[40320*3];
bool vis[40320*3];

int contor(int t)
{
    int num=0,k=0;
    for(int i=1;i<=8;i++)
    {
        k=0;
        for(int j=i+1;j<=8;j++)
            if(p[t].a[i]>p[t].a[j]) 
                k++;
        num+=k*fac[8-i];
    }
    return num;
}


void init()
{
    for(int i=1;i<=4;i++)
        p[1].a[i]=i;
    for(int i=5;i<=8;i++)
        p[1].a[i]=13-i;
    vis[contor(1)]=1;
}

void out(int t)
{
    if(t==1)
        return;
    out(f[t]);
    if(f[t]==1)
        cout<<tot<<endl;
    if(p[t].n==1)
        cout<<"A";
    if(p[t].n==2)
        cout<<"B";
    if(p[t].n==3)    
        cout<<"C";
}

void A(int t)
{
    swap(p[t].a[1],p[t].a[5]);
    swap(p[t].a[2],p[t].a[6]);
    swap(p[t].a[3],p[t].a[7]);
    swap(p[t].a[4],p[t].a[8]);
}

void B(int t)
{
    swap(p[t].a[4],p[t].a[3]);swap(p[t].a[8],p[t].a[7]);
    swap(p[t].a[3],p[t].a[2]);swap(p[t].a[7],p[t].a[6]);
    swap(p[t].a[2],p[t].a[1]);swap(p[t].a[6],p[t].a[5]);
}

void C(int t)
{
    swap(p[t].a[2],p[t].a[3]);
    swap(p[t].a[2],p[t].a[7]);
    swap(p[t].a[2],p[t].a[6]);
}


void bfs()
{
    int h=0,t=1;
    p[1].step=0;
    while(h<=t)
    {
        h++;
        for(int i=1;i<=3;i++)
        {
            t++;
            for(int j=1;j<=8;j++)
                p[t].a[j]=p[h].a[j];
            if(i==1) A(t);
            if(i==2) B(t);
            if(i==3) C(t);
            bas=contor(t);
            if(vis[bas]) t--;
            else
            {
                vis[bas]=1;
                p[t].step=p[h].step+1;
                p[t].n=i;
                tot=p[t].step;
                f[t]=h;
                if(goal==bas)
                {
                    out(t);
                    return ;                    
                }
            }                            
        }
    }
}

int main()
{
//    freopen("msquare.in","r",stdin);
//    freopen("msquare.out","w",stdout);
    init();//建立基本态
    for(int i=1;i<=4;i++)
        cin>>p[0].a[i];
    for(int i=5;i<=8;i++)
        cin>>p[0].a[13-i];
    goal=contor(0);
    if(vis[goal]) 
    {
        cout<<0<<endl;
        return 0;
    }
    bfs();
    cout<<endl;
    return 0;
}

 

posted @ 2017-07-25 10:20  Captain_fcj  阅读(249)  评论(0编辑  收藏  举报