题目传送门
这道题是BFS(广度优先搜索)的一道变形题,但是他的核心算法也是BFS的那一套。这种题比较具有代表性。
有请题目:
题目描述
玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串,(2=< N <=13)该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。
输入描述:
输入包含多组测试数据,每组测试数据由两行组成。
第一行为一个整数N,代表字符串的长度(2<=N<=13)。
第二行为一个仅由0、1、2组成的,长度为N的字符串。
输出描述:
对于每组测试数据,若可以解出密码,输出最少的移位次数;否则输出-1。
示例1
输入
5
02120
输出
1
这种类型的题,我看到以后我的第一反应就是要遍历出每一种情况(当然如果你有更好的方案的话,欢迎留言交流,共同学习)。既然我们要遍历出每一种情况的话搜索就成了一个很好的选择。
我们注意一下题目中的信息:
①字符串的长度在 [2,13]之间数据并不大,我们用搜索的方式并不会出现超时的情况。
②存在不出现2012的情况!(我在程序中并没有对于这种情况进行优化,如果大家想对程序进行优化的话可以通过这个方面,ps:检查字符串中是否有俩个‘2’,‘1’,‘0’,存在的话必定通过有限次交换可以出现2012字符串)
代码:
#include<iostream>
#include<string>
#include<queue>
#include<map>
using namespace std;
struct StrNodeStep {
StrNodeStep(string a,int s)
:str(a)
,step(s)
{}
string str;
int step;
};
//申请一个map来存储我们走过的节点
map<string, int> vis;
//交换函数
string swap(string str,int x,int y)
{
char a = str[x];
str[x] = str[y];
str[y] = a;
return str;
}
//检查当前字符串中是否有“2012”字符串
bool cheak(string str)
{
if (str.size() <= 3)return false;
for (int i=0; i<(str.size()-3); i++)
{
if (str[i] == '2'&&str[i+1] == '0'
&& str[i+2] == '1' && str[i+3] == '2')
return true;
}
return false;
}
int bfs(string str,int num)
{
//想队列
StrNodeStep fri = StrNodeStep(str, 0);
queue<StrNodeStep> q;
q.push(fri);
while (!q.empty())
{
StrNodeStep node = q.front();
//标记走过的节点
vis[node.str] ++;
//当前存在2012字符串
if (cheak(node.str)) return node.step;
q.pop();
//记录当前步数
int step = ++node.step;
//遍历字符串相邻替换
for (int i = 0; i < num-1; i++)
{
string s = swap(node.str, i, i + 1);
if (vis.find(s)==vis.end())
{
StrNodeStep node = StrNodeStep(s, step);
q.push(node);
}
}
}
return -1;
}
int main()
{
int num;
string str;
while (cin >> num>>str)
{
vis.clear();
cout << bfs( str, num) << endl;
}
return 0;
}