问题描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
123.46758
样例输出
3
样例输入
13524678.
46758123.
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 }