题目描述

玛雅人有一种密码,如果字符串中出现连续的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


思路: 自己用dfs写的只过了60%,看了看题解是用bfs 做的,真香! 首先将字符串 str 看做根节点,交换一次的字符串作为第二层,以此类推,直到出现有 "2012"的字符串,那么它的深度就是交换次数。

 

#include <iostream>
#include <map>
#include <queue>
#include <string>

using namespace std;
queue<string> q ;
map<string,int> m ;
int n ;
string str ;
string Swap(string s,int i ) {
char t ;
t = s[i] ;
s[i] = s[i+1] ;
s[i+1] = t ;
return s ;
}
bool check1(string str ) {
if(str.find("0")== string::npos )
return true ;
else if (str.find("1")== string::npos){
return true;
}
else if(str.find("2")== string::npos){
return true ;
}
return false ;

}
int bfs(string str) {
string newstr ;
m.clear() ;
while(!q.empty()) {
q.pop() ;
}
q.push(str) ;
m[str] = 0 ;
while(!q.empty()) {
str = q.front() ;
q.pop( ) ;
for(int i = 0 ; i<(int)str.length()-1 ; i++ ) {
newstr = Swap(str,i) ;
if(m.find(newstr) == m.end()) {//第一次出现
m[newstr] = m[str] + 1 ;
if(newstr.find("2012") !=string::npos) {
return m[newstr] ;
}
else {
q.push(newstr) ;
}
}
}
}
return -1 ;
}
int main() {

while(cin >>n){
cin >> str ;
if(n<4) { // 如果小于4一定组不成2012
cout<<"-1"<<endl ;
}
else if(check1(str)) {//特判
cout<<"-1"<<endl;
}
else {
if(str.find("2012") !=string::npos) {
cout<<"0"<<endl ; //如果根节点包含
}
else {
cout<<bfs(str)<<endl;
}

}



}


return 0 ;
}