九度 题目1482:玛雅人的密码
原题OJ链接:http://ac.jobdu.com/problem.php?pid=1482
题目描述:
玛雅人有一种密码,如果字符串中出现连续的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。
样例输入:
5
02120
样例输出:
1
解题思路:
BFS
压入队列的每一种状态都是(strtmp, step+1),其中strtmp为交换相邻位置一次后的字符串,该字符串之前没有出现过 ,即 M.find(strtmp)==M.end()
,原先的step加上1之后把状态(strtmp,step+1)压入队列。
源代码:
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
using namespace std;
struct MoveStr{
string str;
int step;
};
int size;//记录string在map集合中的位置,每加入一个新的字符串size加1
queue<MoveStr> Q;
map<string,int> M;
/*查找所给字符串是否在集合中,若不在集合中,
则将新的结构体变量压入队列*/
bool check(string str){//检查字符串是否满足2012的条件
int len=str.length();
for(int i=0;i<len-3;i++){
if(str[i]=='2' && str[i+1]=='0' &&
str[i+2]=='1' && str[i+3]=='2'){
return true;
}
}
return false;
}
int BFS(){
while(Q.empty()==false){
MoveStr head=Q.front();//取出队首元素
Q.pop();
if(check(head.str)){//若字符串满足2012的条件,返回移位操作的最小次数
return head.step;
}
for(int i=0;i<head.str.length()-1;i++){
string strtmp=head.str;
//移位一次,交换两个相邻字符
char chartmp=strtmp[i];
strtmp[i]=strtmp[i+1];
strtmp[i+1]=chartmp;
if(M.find(strtmp)==M.end()){
/*检查移位一次之后的字符串strtmp是否在map集合中,
若不在,find()函数返回M.end(),则将(strcmp,step+1)入队
*/
MoveStr tmp;
tmp.str=strtmp;
tmp.step=head.step+1;//移位次数+1
Q.push(tmp);
M[strtmp]=size++;
}
}
}
return -1;
}
int main(){
int n;
while(cin>>n){
while(Q.empty()==false) Q.pop();//初始化队列,清空队列
M.clear();//清空一个map
size=0;
string str;
cin>>str;
M[str]=size++;
MoveStr s;
s.str=str;
s.step=0;
Q.push(s);
int result=BFS();
cout<<result<<endl;
}
return 0;
}