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