【蓝桥杯】历届试题 九宫重排
问题描述如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。输入格式输入第一行包含九宫的初态,第二行包含九宫的终态。输出格式输出最少的步数,如果不存在方案,则输出-1。样例输入12345678.
123.46758样例输出3样例输入13524678.
46758123.样例输出22
【解题思路】
抽象为图模型,空格开始上下左右四个方向搜索,因为求最短路径,用bfs
九个格子的各种变换一共有 9! 种, 用康托展开将各种状态映射为一个数字
然后用一个数组 status[400000]记录各种状态是否到达过
【代码】
1 #include<iostream> 2 #include<queue> 3 #include<cstring> 4 using namespace std; 5 6 int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //x, y 上 -1 0 下 1 0 左 0 -1 右 0 1 7 int fa[10] = { 1, 1, 2, 6, 24 }; 8 int status[400000]; //记录每种状态 9 10 struct Node{ 11 int x, y; // 记录 . 的坐标 12 char s[12]; //记录状态 13 int status; 14 int pos; //记录 . 在s[12]中的下标 15 int step; //到这个状态最少所用的步数 16 }; 17 18 //获得1! ~ 9! 19 void getfa(){ 20 for(int i = 5; i<=9; ++i){ 21 fa[i] = fa[i-1] * i; 22 } 23 } 24 25 //康托展开 26 int cantor(char * s){ 27 int ans = 0; 28 for(int i=0;i<9;++i){ 29 int num = 0; 30 for(int j=i+1;j<9;++j){ 31 if(s[j]<s[i]) num++; 32 } 33 ans = ans + num*fa[8-i]; 34 } 35 return ans; 36 } 37 38 39 void bfs(){ 40 Node beginnode; 41 char end[12], temps[12]; //初始位置 42 scanf("%s%s", beginnode.s, end); 43 beginnode.status = cantor(beginnode.s); 44 for(int i=0;i<3;++i){ 45 for(int j=0;j<3;++j){ 46 if(beginnode.s[i*3+j] == '.'){ 47 beginnode.x = i; 48 beginnode.y = j; 49 beginnode.pos = i*3+j; 50 } 51 } 52 } 53 beginnode.step = 0; 54 int endc = cantor(end); 55 56 queue<Node> q; 57 q.push(beginnode); 58 status[beginnode.status] = 1; 59 60 while(!q.empty()){ 61 Node cur = q.front(); 62 q.pop(); 63 if(endc == cur.status){ 64 printf("%d", cur.step); 65 return; 66 } 67 68 Node addnode; 69 for(int i=0;i<4;++i){ 70 int nx = cur.x + dir[i][0]; 71 int ny = cur.y + dir[i][1]; 72 int np = nx * 3 + ny; 73 if(nx>=0 && nx<=2 && ny>=0 && ny<=2){ 74 for(int j=0;j<9;++j){ 75 addnode.s[j] = cur.s[j]; 76 } 77 addnode.s[cur.pos] = cur.s[np]; 78 addnode.s[np] = cur.s[cur.pos]; 79 addnode.status = cantor(addnode.s); 80 if(status[addnode.status] == 0){ 81 addnode.x = nx; 82 addnode.y = ny; 83 addnode.pos = np; 84 addnode.step = cur.step+1; 85 status[addnode.status] = 1; 86 q.push(addnode); 87 } 88 } 89 } 90 } 91 printf("-1"); 92 } 93 94 int main(){ 95 memset(status, 0, sizeof(status)); 96 getfa(); 97 bfs(); 98 return 0; 99 }
最开始,判断位置出现了错误。。。。
将二维坐标转化为一维,然后四个方向分别+1,-1,+3,-3
苦思不得其解,就测试写了个打印路径的,一看就清楚了
#include<iostream> #include<queue> #include<cstring> #include<vector> using namespace std; int dir[4] = {-3, 3, -1, 1}; //x, y 上 -3 下 +3 左 -1 右 +1 int fa[10] = { 1, 1, 2, 6, 24 }; int status[400000]; //记录每种状态 //test int testid = -1; char test[400000][12]; struct Node{ char s[12]; int status; int pos; int step; vector<int> ids; }; void getfa(){ for(int i = 5; i<=9; ++i){ fa[i] = fa[i-1] * i; } } int cantor(char * s){ int ans = 0; for(int i=0;i<9;++i){ int num = 0; for(int j=i+1;j<9;++j){ if(s[j]<s[i]) num++; } // cout << " num " << num << endl; ans = ans + num*fa[8-i]; } return ans; } void bfs(){ Node beginnode; char end[12], temps[12]; //初始位置 scanf("%s%s", beginnode.s, end); beginnode.status = cantor(beginnode.s); for(int i=0;i<9;++i){ if(beginnode.s[i]=='.'){ beginnode.pos = i; break; } } beginnode.step = 0; int endc = cantor(end); queue<Node> q; //////////// beginnode.ids.push_back(++testid); for(int k=0;k<9;++k){ test[testid][k] = beginnode.s[k]; } q.push(beginnode); status[beginnode.status] = 1; while(!q.empty()){ Node cur = q.front(); // for(int i=0;i<9;++i) cout << cur.s[i]; // cout << " " << cur.status << endl; // for(int i=0;i<9;++i){ // if(i%3==0){ // cout << endl; // } // cout << cur.s[i]; // } // cout << endl; // getchar(); q.pop(); if(endc == cur.status){ for(int kk=0;kk<cur.ids.size();++kk){ for(int jj=0;jj<9;++jj){ if(jj%3==0){ cout << endl; } cout << test[cur.ids[kk]][jj]; } cout << endl; } return; } Node addnode; for(int i=0;i<4;++i){ int np = cur.pos + dir[i]; if(np>=0 && np<=8){ for(int j=0;j<9;++j){ addnode.s[j] = cur.s[j]; } addnode.s[cur.pos] = cur.s[np]; addnode.s[np] = cur.s[cur.pos]; addnode.status = cantor(addnode.s); if(status[addnode.status] == 0){ addnode.pos = np; addnode.step = cur.step+1; status[addnode.status] = 1; ///// addnode.ids.assign(cur.ids.begin(), cur.ids.end()); addnode.ids.push_back(++testid); for(int k=0;k<9;++k){ test[testid][k] = addnode.s[k]; } q.push(addnode); } } } } printf("-1"); } int main(){ memset(status, 0, sizeof(status)); getfa(); bfs(); return 0; }