20190801 bfs判重 | 魔板

洛谷2730魔板

题目背景

在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有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个字符。

  1 /*
  2 如何判断重复状态??如果每一位枚举的话就太慢了,而且耗空间;
  3 那么可不可以用八进制数来存呢?也不行,这样数组开的太大,会爆空间;
  4 于是我们用康托展开,康托就是某数所在全排列中的排序
  5 bfs少不了queue啦
  6 这里queue存的是上一状态的编号,这里另外使用了一个编号
  7 然后枚举三种操作,判断去重后,记录他的编号,上一状态编号,当前状态步数以及达到当前状态的操作,加入队列即可 
  8 最后达到目标状态递归输出即可 
  9 */
 10 #include<cstdio>
 11 #include<queue>
 12 using namespace std;
 13 struct node
 14 {
 15     int a[3][5];
 16 }start,goal,c[500005];
 17 int goalnum,startnum;
 18 int v[500005];
 19 int jc[9] = {1,1,2,6,24,120,720,5040,423360};
 20 int step[500005],fa[500005],cnt,op[500005];
 21 queue< int>q;
 22 int kangtuo(node x)
 23 {
 24     int res = 0;
 25     int mid[9];
 26     for(int i = 1;i <= 4;i ++)mid[i] = x.a[1][i];
 27     for(int i = 4;i >= 1;i --)mid[9 - i] = x.a[2][i];
 28     for(int i = 1;i <= 8;i ++)
 29     {
 30         int midres = 0;
 31         for(int j = i + 1;j <= 8;j ++)
 32         {
 33             if(mid[j] < mid[i])
 34             {
 35                 midres ++;
 36             }
 37         }
 38         res += midres * jc[8 - i];
 39     }
 40     return res;
 41 }
 42 node change(int k,int u)
 43 {
 44     node res;
 45     if(k == 1)
 46     {
 47         for(int i = 1;i <= 4;i ++)res.a[2][i] = c[u].a[1][i];
 48         for(int i = 1;i <= 4;i ++)res.a[1][i] = c[u].a[2][i];
 49     }
 50     else if(k == 2)
 51     {
 52         res.a[1][1] = c[u].a[1][4];res.a[2][1] = c[u].a[2][4];
 53         for(int i = 2;i <= 4;i ++)res.a[1][i] = c[u].a[1][i - 1];
 54         for(int i = 2;i <= 4;i ++)res.a[2][i] = c[u].a[2][i - 1];
 55     }
 56     else if(k == 3)
 57     {
 58         res = c[u];
 59         res.a[1][2] = c[u].a[2][2];
 60         res.a[1][3] = c[u].a[1][2];
 61         res.a[2][3] = c[u].a[1][3];
 62         res.a[2][2] = c[u].a[2][3];
 63     }
 64     return res;
 65 }
 66 void print(int x)
 67 {
 68     if(x == 1)return ;
 69     print(fa[x]);
 70     if(op[x] == 1)printf("A");
 71     else if(op[x] == 2)printf("B");
 72     else if(op[x] == 3)printf("C");
 73 }
 74 void bfs()
 75 {
 76     while(!q.empty())
 77     {
 78         int u = q.front();
 79         q.pop();
 80         for(int i = 1;i <= 3;i ++)
 81         {
 82             node too = change(i,u);
 83             int midnum = kangtuo(too);
 84             if(!v[midnum])
 85             {
 86                 v[midnum] = 1;
 87                 c[++cnt] = too;//别忘了++cnt啊 
 88                 fa[cnt] = u;
 89                 step[cnt] = step[u] + 1;
 90                 op[cnt] = i;
 91                 if(midnum == goalnum)//这里判断会节省几步 
 92                 {
 93                     printf("%d\n",step[cnt]);
 94                     print(cnt);
 95                     return ;
 96                 }
 97                 q.push(cnt);
 98             }
 99         }
100     }
101 }
102 int main()
103 {
104     for(int i = 1;i <= 4;i ++)start.a[1][i] = i;
105     for(int i = 4;i >= 1;i --)start.a[2][i] = 9 - i;
106     for(int i = 1;i <= 4;i ++)scanf("%d",&goal.a[1][i]);
107     for(int i = 4;i >= 1;i --)scanf("%d",&goal.a[2][i]);
108     startnum = kangtuo(start);
109     v[startnum] = 1;
110     goalnum = kangtuo(goal);
111     if(startnum == goalnum)
112     {
113         printf("0");
114         return 0;
115     }
116     c[++cnt] = start;
117     step[cnt] = 0;
118     fa[cnt] = cnt;
119     op[cnt] = 0;
120     q.push(1);
121     bfs();
122     return 0;
123 }

猜你喜欢

转载自www.cnblogs.com/djfuuxjz/p/11281668.html