九宫重排

Posted zww-kjj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了九宫重排相关的知识,希望对你有一定的参考价值。

问题描述
  如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
技术图片技术图片
  我们把第一个图的局面记为:12345678.
  把第二个图的局面记为:123.46758
  显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
  本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
  输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
  输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
样例输入
13524678.
46758123.
样例输出
22
 
题解:
  九宫重排,迷宫问题的最短路问题都是可以用广度优先搜索算法来解决的,具体就是以当前状态为起点,遍历其周围的各个结点,把它们分别放在队列中,在对当前状态处理完之后,就可以进行当前状态的迭代了
  注意,上面的"状态"必须的完整的,因为他周围的每个后继状态都需要当前的完整信息,这样才能进行下一次迭代,进行完备的广度搜索.
  对于此题,具体就是:当前矩阵,步数,空格位置.
 
代码示例:
 
  1 #include<iostream>
  2 #include<queue>
  3 using namespace std;
  4 int dir[]={0,1,0,-1,0};//方向 
  5 int jc[10] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};//0-9的阶乘
  6 bool visit_kt[1000000]={false};//康托visit判断 
  7 struct node
  8 {//状态 
  9     char str[10];
 10     int step;
 11     int spx,spy;
 12 };
 13 bool check(node &start,node &end)
 14 {//检测是否成功 
 15     for(int j=0;j<9;j++)
 16         if(start.str[j]!=end.str[j]) return false; 
 17     return true;
 18  } 
 19 void init(node &start,node &end)
 20 {
 21 //初始态,终态的初始化 
 22     for(int j=0;j<9;j++)
 23     {
 24         scanf("%c",&start.str[j]);
 25         if(start.str[j]==.) 
 26         {
 27             start.spx=j/3+1;
 28             start.spy=j%3;
 29             start.step=0;
 30         }
 31     }
 32     getchar();
 33     for(int j=0;j<9;j++)
 34     {
 35         scanf("%c",&end.str[j]);
 36         if(end.str[j]==.) 
 37         {
 38             end.spx=j/3+1; end.spy=j%3;
 39             end.step=0;
 40         }
 41     }
 42 }
 43 void print(string a)
 44 {//打印,状态的矩阵 
 45     cout<<"-------------"<<endl;
 46     for(int i=0;i<3;i++)
 47     {
 48         for(int j=0;j<3;j++)
 49         {
 50             int index=i*3+j;
 51             cout<<a[index]<<" ";
 52         }
 53         cout<<"-----------"<<endl;
 54     }
 55 }
 56 int por(string a)//康托展开
 57 {
 58     int size = 0;
 59     for (int i = 0; i < 9; i++) {
 60         int len = 0;
 61         for (int j = i + 1; j < 9; j++) {
 62             if (a[i] > a[j])len++;
 63         }
 64         size += len * jc[9-i-1];
 65     }
 66     return size;
 67 }
 68 
 69 int main()
 70 {
 71     queue<node> q;
 72     node start,end;
 73     int count=0;
 74     init(start,end);
 75     q.push(start);
 76     if(check(start,end)) 
 77     {//防止数据太狗 
 78         cout<<0<<endl; return 0;
 79     }
 80     while(!q.empty())
 81     {
 82         node local=q.front();
 83         q.pop();
 84         for(int i=0;i<4;i++)
 85         {
 86             node temp=local;
 87             int x=local.spx,y=local.spy;
 88             x=x+dir[i]; y=y+dir[i+1];//后继空格的位置 
 89             if(x<0||x>2||y<0||y>2) continue;
 90             temp.str[3*(local.spx)+local.spy]=temp.str[3*(x)+y];
 91             temp.str[3*(x)+y]=.;
 92             temp.spx=x; temp.spy=y;//空格
 93             /*以上都是为了得出temp结点(状态),*/ 
 94             int index=por(temp.str);//康托值 
 95             if(!visit_kt[index])
 96             {// 
 97                 if(check(temp,end))
 98                 {//判断是否成功 
 99                     cout<<temp.step<<endl;
100                     cout<<temp.str<<endl;
101                     return 0;
102                 }
103                 visit_kt[index]=true;
104                 temp.step++;
105                 q.push(temp);//入队 
106                 if(count<10)//test it 
107                     print(temp.str);
108                 count++;
109             }
110         }
111     }
112     cout<<"no"<<endl; 
113     return 0;
114 }

 

 
 
 

以上是关于九宫重排的主要内容,如果未能解决你的问题,请参考以下文章

BFS解决九宫重排问题

九宫重排

九宫重排_康拓展开_bfs

算法笔记_183:历届试题 九宫重排(Java)

一只蒟蒻的刷题历程蓝桥杯历届试题 九宫重排 (八数码问题:BFS+集合set)

算法之美--2.3.3九宫格问题