魔板 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: 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 之间)不换行,表示目标状态。
输出格式:
Line 1: 包括一个整数,表示最短操作序列的长度。
Line 2: 在字典序中最早出现的操作序列,用字符串表示,除最后一行外,每行输出60个字符。
思路:
广搜应该大家都知道,但是状态怎么存?(8^8的数组绝对爆空间)
(大佬:康拓展开)
我不会啊qwq
没办法喽,只能从排列数来看
8!,空间装得下
那么我们就该想一下怎么算位置了
比如说一个状态
4 1 2 3
8 5 6 7
我们按着行来算,化成一个数字
41238567
在这个数据前有多少个排列呢?
我们一位一位看
首先,看第一位
此时没有用过且比4小的数有1 2 3 三个
所以就有7!*3个数在他前面
再看第二位
没有比他小的数,跳过
一位一位地算,就可以知道有多少个比他小的排列
最后+1,就是编号喽
需要调换的时候编号转状态是同理的
广搜就好喽
注意:他的数据为顺时针给出,我的程序为按行读入
所以初始状态1 2 3 4 5 6 7 8
在我这里的映射为
1 2 3 4
8 7 6 5
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define rii register int i #define rij register int j using namespace std; bool bj[40325]; int n; struct que{ int zt,sd,pre,cz; }q[40325]; int st,jc[10]={0,1,2,6,24,120,720,5040,40320},cnt; int ans[100005]; int change(int xl) { int mc=1; int ls[10]={0,0,0,0,0,0,0,0,0,0}; int sy[10]={0,0,0,0,0,0,0,0,0,0}; for(rii=8;i>=1;i--) { ls[i]=xl%10; xl/=10; } for(rii=1;i<=7;i++) { int ltt=ls[i]; for(rij=1;j<=ltt-1;j++) { if(sy[j]!=1) { mc+=jc[8-i]; } } sy[ltt]=1; } return mc; } void add(int bh,int pre,int cz) { cnt++; q[cnt].cz=cz; q[cnt].pre=pre; q[cnt].zt=bh; q[cnt].sd=q[pre].sd+1; } void A(int bh,int pre) { bh--; int ls[10]={0,0,0,0,0,0,0,0,0,0}; int sy[10]={0,0,0,0,0,0,0,0,0,0}; for(rii=1;i<=7;i++) { int ltt=bh/jc[8-i]; bh-=ltt*jc[8-i]; int sl=0; for(rij=1;j<=8;j++) { if(sy[j]!=1) { sl++; } if(sl==ltt+1) { sy[j]=1; ls[i]=j; break; } } } for(rii=1;i<=8;i++) { if(sy[i]==0) { ls[8]=i; break; } } memset(sy,0,sizeof(sy)); for(rii=1;i<=4;i++) { int kkk=ls[i]; ls[i]=ls[i+4]; ls[i+4]=kkk; } int mc=1; for(rii=1;i<=7;i++) { int ltt=ls[i]; for(rij=1;j<=ltt-1;j++) { if(sy[j]!=1) { mc+=jc[8-i]; } } sy[ltt]=1; } if(bj[mc]!=1) { add(mc,pre,1); bj[mc]=1; } } void B(int bh,int pre) { bh--; int ls[10]={0,0,0,0,0,0,0,0,0,0}; int sy[10]={0,0,0,0,0,0,0,0,0,0}; for(rii=1;i<=7;i++) { int ltt=bh/jc[8-i]; bh-=ltt*jc[8-i]; int sl=0; for(rij=1;j<=8;j++) { if(sy[j]!=1) { sl++; } if(sl==ltt+1) { sy[j]=1; ls[i]=j; break; } } } for(rii=1;i<=8;i++) { if(sy[i]==0) { ls[8]=i; break; } } memset(sy,0,sizeof(sy)); int a1=ls[4]; int b1=ls[8]; for(rii=4;i>=2;i--) { ls[i]=ls[i-1]; ls[i+4]=ls[i+3]; } ls[1]=a1; ls[5]=b1; int mc=1; for(rii=1;i<=7;i++) { int ltt=ls[i]; for(rij=1;j<=ltt-1;j++) { if(sy[j]!=1) { mc+=jc[8-i]; } } sy[ltt]=1; } if(bj[mc]!=1) { add(mc,pre,2); bj[mc]=1; } } void output(int fi) { int len=q[fi].sd; printf("%d\n",len); int wz=fi; for(rii=len;i>=1;i--) { ans[i]=q[wz].cz; wz=q[wz].pre; } int cnt=0; for(rii=1;i<=len;i++) { if(ans[i]==1) { putchar('A'); continue; } if(ans[i]==2) { putchar('B'); continue; } else { putchar('C'); } cnt++; if(cnt==60) { puts(""); cnt=0; } } } void C(int bh,int pre) { bh--; int ls[10]={0,0,0,0,0,0,0,0,0,0}; int sy[10]={0,0,0,0,0,0,0,0,0,0}; for(rii=1;i<=7;i++) { int ltt=bh/jc[8-i]; bh-=ltt*jc[8-i]; int sl=0; for(rij=1;j<=8;j++) { if(sy[j]!=1) { sl++; } if(sl==ltt+1) { sy[j]=1; ls[i]=j; break; } } } for(rii=1;i<=8;i++) { if(sy[i]==0) { ls[8]=i; break; } } memset(sy,0,sizeof(sy)); int a2=ls[2],a3=ls[3],b2=ls[6],b3=ls[7]; ls[3]=a2; ls[2]=b2; ls[6]=b3; ls[7]=a3; int mc=1; for(rii=1;i<=7;i++) { int ltt=ls[i]; for(rij=1;j<=ltt-1;j++) { if(sy[j]!=1) { mc+=jc[8-i]; } } sy[ltt]=1; } if(bj[mc]!=1) { add(mc,pre,3); } bj[mc]=1; } int main() { scanf("%d",&st); for(rii=2;i<=4;i++) { int ltt; st*=10; scanf("%d",<t); st+=ltt; } st*=10000; int sr; scanf("%d",&sr); st+=sr; scanf("%d",&sr); st+=sr*10; scanf("%d",&sr); st+=sr*100; scanf("%d",&sr); st+=sr*1000; int fi=change(st); q[1].zt=24; bj[24]=1; cnt=1; for(rii=1;i<=cnt;i++) { int z=q[i].zt; if(z==fi) { output(i); return 0; } A(z,i); B(z,i); C(z,i); } }