宽搜经典题之三——魔板+康托展开

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了宽搜经典题之三——魔板+康托展开相关的知识,希望对你有一定的参考价值。

  宽搜的实现主要使用了队列,从起点出发,遇到合法的点,就放入队列尾。每次取队列头进行处理,探索到新元素就放在队尾。如果队列中元素全部处理完也没有发现目标,则不存在这样的路径。遇到目标点之后,搜索结束。

  深搜比较适合解决路径的存在性问题,只要发现一个路径存在,搜索结束。深搜在实现上,一般使用递归和回溯。从起点出发,依次探索四个相邻单元,如果下一单元合法且不是目标点,则标记此点,递归,如果递归结束后,表明从这个方向的所有路径均不能到达目标,则取消标记,回溯。

     深搜往往和回溯相关,所谓回溯,就是当当前路径走不通,递归结束时,将标记的状态变回递归之前的状态,好从新选择方向。而当求最短路径的问题时,往往标记已经走过的路径,防止重复,造成无限循环。

 

好了,魔板该上了。

还是caioj上的。

1047: 宽搜2(魔板)

时间限制: 1 Sec  内存限制: 128 MB
提交: 91  解决: 39
[提交][状态][讨论版]

题目描述

【题目描述】
在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。
这是一张有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:
8 7 6 5
1 2 3 4
B:
4 1 2 3
5 8 7 6
C:
1 7 2 4
8 6 3 5
对于每种可能的状态,这三种基本操作都可以使用。
你要编程计算用最少的基本操作完成基本状态到目标状态的转换,输出基本操作序列。
【输入格式】
只有一行,包括8个整数,用空格分开(这些整数在范围 1——8 之间),表示目标状态。
【输出格式】
第一行包括一个整数,表示最短操作序列的长度。
第二行在字典序中最早出现的操作序列,用字符串表示,除最后一行外,每行输出60个字符。
【样例输入】
2 6 8 4 5 7 3 1
【样例输出】
7
BCABCCB

样例输入

2 6 8 4 5 7 3 1

样例输出

7
BCABCCB

上马:

#include<iostream>

#include<queue>

#include<cstring>

#include<algorithm>

using namespace std;

const int fac[]={1,1,2,6,24,120,720,5040,5040*8};

struct node

{

         int s[8],step;

         char ch;

         node *pre;

         node():pre(NULL),step(0){ };

};

node b,e;

bool f[50000];

queue<node> q;

 

void init()

{

         ios::sync_with_stdio(false);

         for (int i=0;i<8;i++) b.s[i]=i+1;

         swap(b.s[4],b.s[7]),swap(b.s[5],b.s[6]);

         for (int i=0;i<8;i++) cin>>e.s[i];

         swap(e.s[4],e.s[7]),swap(e.s[5],e.s[6]);

         memset(f,0,sizeof(f));

}

 

int cantor(const node &x) //康托展开精髓之处

{

         int t(0),d;

         for (int i=0;i<8;i++)

         {

                   d=0;

                   for (int j=i+1;j<8;j++)

                            if (x.s[j]<x.s[i])

                                     d++;

                   t+=d*fac[7-i];

         }

         return t+1; //这个数就是其单独的编号

}

 

bool issame(const node &x,const node &y)

{

         for (int i=0;i<8;i++)

                   if (x.s[i]!=y.s[i])

                            return false;

         return true;

}

 

void output(node *p)

{

         if (p->pre==NULL) return;

         output(p->pre);

         cout<<p->ch;

         return;

}

 

void bfs(const node &b,const node &e)

{

         q.push(b);

         f[cantor(b)]=true;

         node *u;

         node v;

         int t;

         while (!q.empty())

         {

                   u=new node;//每次要新开辟,不然就会覆盖!

                   *u=q.front();

                   if (issame(*u,e))

                   {

                            cout<<u->step<<endl;

                            output(u);

                            cout<<endl;

                            return;

                   }

                   q.pop();

                   for (char c=‘A‘;c<=‘C‘;c++)

                   {       

                            v=*u;

                            switch (c)

                            {

                                     case ‘A‘:

                                               for (int i=0;i<4;i++) swap(v.s[i],v.s[i+4]);

                                               if (f[cantor(v)]) break;

                                               v.step++;

                                               v.pre=u;

                                               v.ch=c;

                                               q.push(v);

                                               f[cantor(v)]=true;

                                               break;

                                     case ‘B‘:

                                               t=v.s[3];

                                               for (int i=3;i>0;i--) v.s[i]=v.s[i-1];

                                               v.s[0]=t;

                                               t=v.s[7];

                                               for (int i=7;i>4;i--) v.s[i]=v.s[i-1];

                                               v.s[4]=t;

                                               if (f[cantor(v)]) break;

                                               v.step++;

                                               v.pre=u;

                                               v.ch=c;

                                               q.push(v);

                                               f[cantor(v)]=true;

                                               break;

                                     case ‘C‘:

                                               t=v.s[1];

                                               v.s[1]=v.s[5];

                                               v.s[5]=v.s[6];

                                               v.s[6]=v.s[2];

                                               v.s[2]=t;

                                               if (f[cantor(v)]) break;

                                               v.step++;

                                               v.pre=u;

                                               v.ch=c;

                                               q.push(v);

                                               f[cantor(v)]=true;

                            }

                   }

         }

}

 

int main()

{

         init();

         bfs(b,e);

         return 0;

}




以上是关于宽搜经典题之三——魔板+康托展开的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 1430 - 魔板( 康托展开 + BFS预处理 )

HDU 1430 魔板(康托展开+BFS+预处理)

P2730 魔板 Magic Squares

八数码难题

魔板 Magic Squares

双向广搜+hash+康托展开 codevs 1225 八数码难题