之前转发过一篇BFS的文章,但是只有一些简单的情况,剩余的一些情况原博主没有进行补充。碰巧我今天刷题刷到了一个BFS的题目,写在这里,做一个补充。如果有机会这个系列还会更新。
例题:Open the Lock
有一个密码锁,由四位的数字组成,每一位的数字是从1到9 中的一个。
对于每一次操作:你可以选择对一个位置上的数字 进行加1或者减1操作。也可以选择交换相邻两位的数字。(注意:对9加1得到的是1,对1减1后得到的是9,且第1位和第4位数字不相邻。)
现在给密码锁的初始状态,以及开锁的最终状态,要求输出打开密码锁的最小步数。
Input:
输入的第一行是T,表示测试样例的数目。
每个测试样例有两行,第一行是一个四位数N,表示密码锁的初始状态,第二行是一个四位数M,表示打开密码锁的密码。
每个测试样例的输入隔有一个空行。
Output:
对于每个测试样例,输出最小步数。
Sample Input:
2
1234
2144
1111
9999
Sample Output:
2
4
思路:看见题目要求最短步骤就可以知道用bfs来解决了,用vis四维数组来标记某个四位数是否存在过;在while里面,分别枚举所有的操作
AC代码:
#include<iostream>
#include <cstring>
#include<queue>
using namespace std;
struct node{
int a[4];
int step; //步数
}first,target;
char s1[4],s2[4];
int vis[11][11][11][11]; //标记某个四位数是否出现
void bfs(){
node s, next;
queue<node> q;
memset(vis,0, sizeof(vis));
s = first;
s.step = 0; //步数置为0
q.push(s);
vis[s.a[0]][s.a[1]][s.a[2]][s.a[3]] = true;
while(!q.empty()){
node t = q.front(); //队首元素放在t中
q.pop();
//如果找到目标,输出
if(t.a[0] == target.a[0] && t.a[1] == target.a[1] && t.a[2] == target.a[2] && t.a[3] == target.a[3]){
printf("%d\n", t.step);
return;
}
for(int i = 0; i < 4; i++){
//枚举四位数,都进行加一操作
next = t; //将t的值赋给next
next.a[i]++;
if(next.a[i] == 10)
next.a[i] = 1;
if(!vis[next.a[0]][next.a[1]][next.a[2]][next.a[3]]){
vis[next.a[0]][next.a[1]][next.a[2]][next.a[3]] = true;
next.step++;
q.push(next);
}
}
for(int i = 0; i < 4; i++){
next = t;
next.a[i]--;
if(next.a[i] == 0)
next.a[i] = 9;
if(!vis[next.a[0]][next.a[1]][next.a[2]][next.a[3]]){
vis[next.a[0]][next.a[1]][next.a[2]][next.a[3]] = true;
next.step++;
q.push(next);
}
}
for(int i = 0; i < 3; i++){
//从左到右交换相邻两个数
next = t;
next.a[i] = t.a[i + 1];
next.a[i + 1] = t.a[i];
if(!vis[next.a[0]][next.a[1]][next.a[2]][next.a[3]]){
vis[next.a[0]][next.a[1]][next.a[2]][next.a[3]] = true;
next.step++;
q.push(next);
}
}
}
}
int main(){
int testNum;
scanf("%d",&testNum);
while (testNum--) {
scanf("%s",s1);
scanf("%s",s2);
for(int i = 0; i < 4; i++){
//把初始值和目标值分别赋给它们
first.a[i] = s1[i] - '0';
target.a[i] = s2[i] - '0';
}
bfs();
if (testNum != 0) getchar();
}
return 0;
}