输入包含多组测试数据,每组测试数据由两行组成。 第一行为一个整数N,代表字符串的长度(2<=N<=13)。 第二行为一个仅由0、1、2组成的,长度为N的字符串。
对于每组测试数据,若可以解出密码,输出最少的移位次数;否则输出-1。
5 02120
1
#include <stdio.h>
#include <queue>
#include <string>
#include <iostream>
using namespace std;
bool pan(string a,int n) {
bool flag=false;
for(int i=0; i<n-3; i++) {
if(a[i]=='2'&&a[i+1]=='0'&&a[i+2]=='1'&&a[i+3]=='2') {
flag=true;
break;
}
}
return flag;
}
string swap(string a,int i,int j) {
char temp=a[i];
a[i]=a[j];
a[j]=temp;
return a;
}
struct E {
string a;
int t;
};
queue<E> Q;
int BFS(int n) {
while(Q.empty()==false) {
E now=Q.front();
Q.pop();
if(pan(now.a,n)){
return now.t;
}
else{
for(int i=0; i<n-1; i++) {
string new_a=swap(now.a,i,i+1);
int new_t=now.t+1;
if(new_t>20) {
return -1;
} else {
if(pan(new_a,n)) {
return new_t;
} else {
E tmp;
tmp.a=new_a;
tmp.t=new_t;
Q.push(tmp);
}
}
}
}
}
return -1;
}
int main() {
int n;
string str;
while(cin>>n>>str) {
while(Q.empty()==false){
Q.pop();
}
E tmp;
tmp.a=str;
tmp.t=0;
Q.push(tmp);
int ans=BFS(n);
printf("%d\n",ans);
}
return 0;
}
#include<iostream>
#include<string>
#include<map>
#include<queue>
using namespace std;
int n;
bool judge(string s)
{
int l=s.size();
for(int i=0;i<l-3;i++)
{
if(s[i]=='2'&&s[i+1]=='0'&&s[i+2]=='1'&&s[i+3]=='2')
{
return true;
}
}
return false;
}
int bfs(string s)
{
map<string,int>mp;//如果遍历过,将second标记为1
mp.clear();//清空上一次的缓存
queue<pair<string,int>>que;//用队列来保存搜索的路径
que.push(make_pair(s,0));//将第一个string入队
while(!que.empty())//如果遍历过所有string,返回-1
{
pair<string,int> now=que.front();
que.pop();//队头的string出队
string str=now.first;
if(judge(str))
return now.second;
if(mp[str])//如果该排列已经judge过,则跳到下一个排列
continue;
mp[str]=1;//如果没有就标记为已遍历过
for(int i=0;i<n-1;i++)//创建新的排列
{
swap(str[i],str[i+1]);
que.push(make_pair(str,now.second+1));
swap(str[i],str[i+1]);
}
}
return -1;
}
int main()
{
string s;
while(cin>>n)
{
cin>>s;
cout<<bfs(s)<<endl;
}
return 0;
}
借鉴了评论区的代码,BFS很赞
经典的bfs搜索
#include<iostream>
#include<queue>
#include<map>
#include<string>
using namespace std;
char Aim[] = "2012";
typedef struct str_cos{ string str; //包含的字符串 int deep; //标示该串做了几次字符交换 str_cos(string str,int deep) { this->deep = deep; this->str = str; }
}STR;
bool SubString(string S){ //判断某个字符串是否包含子串"2012" int p = 0; int q = 0; while(p < S.size()){ if(S[p] == Aim[q]){ q++; } else{ q = 0; } p++; if(q == 4) return true; } return false;
}
int MoveCounter(STR str){ queue<STR> Q; map<string, int> MAP; //用来区分该串是否之前已经生成过 char T; int Length = str.str.size(); string S_temp; Q.push(str); //原始串入队,为接下来的广度遍历做准备 MAP[str.str] = 1; //标示原始串已经访问过,1是看心情给的 while (!Q.empty()) { STR F_temp = Q.front(); Q.pop(); if (SubString(F_temp.str)) //若该串满足题目要求,则输出深度(字符交换次数) return F_temp.deep; for (int i = 0; i < str.str.size() - 1; ++i) { //该循环是用来把当前串的所有可能的相邻交换(一次)列出来 S_temp = F_temp.str; T = S_temp[i]; S_temp[i] = S_temp[i + 1]; S_temp[i + 1] = T; if (MAP.find(S_temp) == MAP.end()) { //若该交换后的新串先前木有出现过,则标示已访问,并入队。 MAP[S_temp] = 1; Q.push(str_cos(S_temp, F_temp.deep + 1)); } } } return -1; }
int main(){ string S; int N; while(scanf("%d",&N) != EOF){ //这个N你可以看心情给! cin>>S; printf("%d\n",MoveCounter(str_cos(S,0))); } return 0;
}
/*
* QQ: 825580813
* 把所有的转换后的字符串都列出来,然后判断这其中是否包含"2012"即可.
*
* 那么如何把他们都列出来呢?
*
* 建立一张图,根据宽度优先遍历即可,(按理说,图有两种遍历,为何偏偏选择宽度优先呢)
* 因为,这张图的建立过程与遍历过程同时进行.
*
* 建立图的方法:
* 将源字符串作为第一个节点, 然后将它的移位字符串作为邻接点即可.
*/
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
class StringNum{
String str;
int num;
public StringNum(String str, int num) {
this.str = str;
this.num = num;
}
}
public class MayanCode {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int n = sc.nextInt();
String code = sc.next();
int moveTime = getMoveTime(code, n);
System.out.println(moveTime);
}
sc.close();
}
private static int getMoveTime(String code, int n) {
if (n < 4) {
return -1;
}
ArrayList<String> record = new ArrayList<>();
Queue<StringNum> que = new LinkedList<>();
StringNum stringNum = new StringNum(code, 0);
que.offer(stringNum);
record.add(code);
while (!que.isEmpty()) {
stringNum = que.remove();
if (stringNum.str.contains("2012")) {
return stringNum.num;
}
for (int i = 0; i < n - 1; ++i) {
char[] temp = stringNum.str.toCharArray();
swap(temp, i, i + 1);
String tempStr = new String(temp);
if (!record.contains(tempStr)) {
record.add(tempStr);
que.offer(new StringNum(tempStr, stringNum.num + 1));
}
}
}
return -1;
}
private static void swap(char[] arr, int i, int j) {
char temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//BFS即可,注意换位后要恢复原样,不然会影响之后的循环
//队列可以不用指针式,直接开成结构体型避免了malloc()申请内存
#include <stdio.h>
#include <string.h>
#define MAXSIZE 200000 //注意自己写队列的时候要开足够大 有个十三位的数据 必须要
//用到二十万的队列 不然结果会是错的,通不过的可以看看是不
//队列爆了
typedef struct passWord{
char str[13];
int n;
int cost;
}passWord;
int isPW(passWord pw){
int n=pw.n;
int i;
for(i=0;i<n-3;i++){
if(pw.str[i]=='2'&&pw.str[i+1]=='0'&&pw.str[i+2]=='1'&&pw.str[i+3]=='2') return 1;
}
return 0;
}
int BFS(passWord pw){
passWord queue[MAXSIZE];
int i;
int front=0,end=0;
queue[end]=pw;
end=(end+1)%MAXSIZE;
while(front!=end){
passWord p=queue[front];
front=(front+1)%MAXSIZE;
if(isPW(p)){
return p.cost;
}else {
for(i=0;i<p.n-1;i++){
char temp = p.str[i];
p.str[i]=p.str[i+1];
p.str[i+1]=temp;
p.cost++;
queue[end]=p;
end=(end+1)%MAXSIZE;
temp = p.str[i];
p.str[i]=p.str[i+1];
p.str[i+1]=temp;
p.cost--;
}
}
}
return -1;
}
int main(){
passWord pw;
int n;
scanf("%d",&n);
scanf("%s",pw.str);
pw.n=n;
pw.cost=0;
printf("%d\n",BFS(pw));
return 0;
}
}
#include<stdio.h>
#include<string>
#include<iostream>
#include<map>
#include<queue>
using namespace std;
bool check(string);
struct node{
string v;
int step;
node(string x,int step):v(x),step(step){}
};
int main(){
int N;
string x;
while(cin>>N){
cin>>x;
if(N<4){
printf("-1\n");
continue;
}
map<string,int> book;
queue<node> Q;
Q.push(node(x,0));
int flag=0,step=-1;
book[x]=1;
while(!Q.empty()){
node head=Q.front();Q.pop();
if(check(head.v)){
//flag=1;
step=head.step;
break;
}
string s=head.v;
for(int i=0;i<=s.length()-2;i++){
string tmp=s;
tmp[i]=s[i+1];
tmp[i+1]=s[i];
if(book.count(tmp)==0){
book[tmp]=1;
Q.push(node(tmp,head.step+1));
}
}
}
printf("%d\n",step);
}
}
bool check(string x){
if(x.length()<4) return false;
int i;
for(i=0;i<=x.length()-4;i++)
if(x[i]=='2'&&x[i+1]=='0'&&x[i+2]=='1'&&x[i+3]=='2')
return true;
return false;
} #include <bits/stdc++.h>
using namespace std;
int flag, res, n;
string s;
bool check(string str) {
for(int i = 0; i <= str.size() - 4; i++) {
if(str.substr(i, 4) == "2012") {
return true;
}
}
return false;
}
void bfs() {
queue<pair<string, int>> q;
q.push({s, 0});
while(!q.empty()) {
auto t = q.front();
q.pop();
if(check(t.first)) {
flag = 1;
res = t.second;
break;
}
for(int i = 0; i < t.first.size() - 1; i++) {
swap(t.first[i], t.first[i + 1]);
q.push({t.first, t.second + 1});
swap(t.first[i], t.first[i + 1]);
}
}
}
int main() {
int n;
cin >> n;
cin >> s;
bfs();
if(flag) {
cout << res << endl;
} else {
cout << -1 << endl;
}
}
#include<iostream>
#include<queue>
#include<string>
using namespace std;
struct state
{
string s;
int t;
state(string s,int t):s(s),t(t){}
};
queue<state> que;
void bfs(string s)
{
state current(s,0);
que.push(current);
while(!que.empty())
{
state num=que.front();
que.pop();
if(num.s.find("2012"))
{
cout<<num.t;
return;
}
else
{
for(int i=0 ; i<num.s.size()-1 ; i++)
{
state next(num.s,num.t+1);
char c=next.s[i];
next.s[i]=next.s[i+1];
next.s[i+1]=c;
que.push(next);
}
}
}
cout<<-1;
}
int main()
{
string code;
return 0;
} #include<iostream>
#include<cstdio>
#include<queue>
#include<string>
#include<map>
using namespace std;
int num;
std::map<string, int> myMap;
void BFS(string str)
{
queue<string> myQueue;
myQueue.push(str);
myMap[str] = 0;
while (!myQueue.empty())
{
string temp = myQueue.front();
myQueue.pop();
if (temp.find("2012") != string::npos)
{
cout << myMap.find(temp)->second << endl;
return;
}
for (int i = 0; i < temp.size() - 1; i++)
{
string temp1 = temp;
char c = temp1[i];
temp1[i] = temp1[i + 1];
temp1[i + 1] = c;
if (myMap.find(temp1) == myMap.end())
{
myQueue.push(temp1);
myMap[temp1] = myMap.find(temp)->second+1;
}
}
}
cout << -1 << endl;
}
int main()
{
string str;
int n;
while (cin >> n >> str)
{
num = 0;
myMap.clear();
BFS(str);
}
return 0;
} #include<iostream>
#include<string>
#include<algorithm>
#include<queue>
#include<unordered_map>
using namespace std;
/*算法:N叉树层次遍历(BFS)*/
int main()
{
int N;
string str;
queue<string> Q;//BFS队列
unordered_map<string, bool> mark;//访问过标记,用哈希查询比较快
while (cin>>N>>str)
{
Q.push(str);
mark[str] = true;
//l_c:当前层最后一个 l_n:下一层最后一个 current:当前字符串
string l_c = str, l_n = "", current = str;
int count = 0;//次数
//只有当缺0||1||2时才无法解密
if (str.find('0') == str.npos
|| str.find('1') == str.npos
|| str.find('2') == str.npos)
count = -1;
else
{
while (str.find("2012") == str.npos)
{
for (unsigned int i = 0; i < N - 1; i++)
{
str = current;
swap(str[i], str[i + 1]);//往右交换相邻字符
if (mark[str] == false)//没访问过的入队
{
Q.push(str);
mark[str] = true;
l_n = str;
}
else
continue;
}
if (current == l_c)//到达当前层最后一个,就要加一层
{
l_c = l_n;
count++;
}
Q.pop();
str = Q.front();
current = str;
}
}
cout << count << endl;
//多组输入善后
while (!Q.empty())
Q.pop();
mark.clear();
}
return 0;
} #include <bits/stdc++.h>
using namespace std;
/*
有连续 2012 -> s.find("2012") != string::npos
相邻的字符移位 -> swap(s[i-1], s[i])
统计移位次数 -> map<string, int>
注意的点:对于2222这样的字符串,其移位后可能会存在相同的字串,要去重
*/
map<string, int> M; //M[s] 表示字符串 s 的已移位次数
int BFS(string s) {
queue<string> Q;
Q.push(s);
M[s] = 0;
while(!Q.empty()) {
string current = Q.front();
if(current.find("2012") != string::npos) { //若找到,返回移位次数
return M[current];
}
Q.pop();
for(int i = 1; i < current.size(); i++) { //遍历分支
string next = current;
swap(next[i - 1], next[i]);
if(M.find(next) == M.end()) { //如果移位后的新字符串还没出现过
M[next] = M[current] + 1; //**则它的移位次数是它父亲的次数+1**
Q.push(next);
}
else { //若已经出现过,抛弃
continue;
}
}
}
return -1; //无法组成,返回-1
}
int main() {
int n;
string s;
while(cin >> n >> s) {
cout << BFS(s) << endl;
}
} #include<bits/stdc++.h>
using namespace std;
struct Status
{
string x;
int t;
Status(string x1,int t1):x(x1),t(t1) {}
};
string change(string x,int n)
{
char ch;
if(n<x.size()-1)
{
ch=x[n];
x[n]=x[n+1];
x[n+1]=ch;
}
return x;
}
void BFS(string x)
{
queue<Status>myqueue;
Status begin(x,0);
myqueue.push(begin);
while(!myqueue.empty())
{
Status current=myqueue.front();
myqueue.pop();
if(current.x.find("2012")!=x.npos)//如果2012在开头那么返回0 得想办法处理
{
cout<<current.t;
break;//找到,那么输出,函数结束
}
current.t=current.t+1;
string x=current.x; //必须先记录下来再去循环,否则循环里面不能实现本意
for(int i=0;i<x.size()-1;i++)//进行广度优先遍历
{
current.x=change(x,i);
myqueue.push(current);
}
}
}
int main()
{
int n;
cin>>n;
string x;
while(cin>>x)
BFS(x);
return 0;
} //BFS算法
#include <iostream>
(720)#include <algorithm>
#include <map>
(747)#include <queue>
#include <set>
using namespace std;
set<string> str_set;
queue<string> str_queue;
bool in_str(string str) //判断2012是否在串中
{
for (int i = 0; i < str.length() - 4; i++)
{
if (str.substr(i, 4) == "2012")
return true;
}
return false;
}
string swap_str(string str, int i, int j) //交换串中i,j位置的值
{
char temp = str[i];
str[i] = str[j];
str[j] = temp;
return str;
}
int get_times(string str)
{
int cnt = 0, index = 0;
if (in_str(str))
return index;
else
{
str_queue.push(str);
str_set.insert(str);
}
bool tag = true;
while (!str_queue.empty() && tag)
{
//cout << "队列长度为:" << str_queue.size() << endl;
int qu_length = str_queue.size();
for (int i = 0; i < qu_length; i++)
{
string s = str_queue.front();
str_queue.pop();
if (in_str(s))
{
tag = false;
index = cnt;
break;
}
for (int j = 0; j < s.length() - 1; j++)
{
string swapped_s = swap_str(s, j, j + 1);
if (str_set.find(swapped_s) == str_set.end())
{
str_queue.push(swapped_s);
str_set.insert(swapped_s);
}
}
}
cnt++;
}
return index;
}
int main()
{
int n;
string str;
while ( cin >> n >> str)
{
int valid[3] = { 0 };
for (auto c : str)
valid[c - '0']++;
if (valid[0] >= 1 && valid[1] >= 1 && valid[2] >= 2)
{
cout << get_times(str) << endl;
}
else
cout << -1 << endl;
}
} #include <bits/stdc++.h>
using namespace std;
struct Code{
string s; //记录当前的字符串
int m; //记录当前移位的次数
Code(string s, int m): s(s), m(m) {}
};
string swap(string nstr, int k){
char tmp;
tmp = nstr[k];
nstr[k] = nstr[k+1];
nstr[k+1] = tmp;
return nstr;
}
map<string, bool> visit; //用一个 map 记录当前的字符串是否在之前出现过
void BFS(string st){
queue<Code> Q;
Q.push(Code(st, 0)); //压入初始状态,此时结构体中的m = 0(移位 0 次)
int len = st.size();
visit[st] = true;
while(!Q.empty()){
Code current = Q.front(); //定义一个结构体 current 表示当前的状态
Q.pop();
if(current.s.find("2012") != string::npos){ //当前状态符合题意,也就是找到了
cout << current.m << endl; //输出 current 结构体中的 m,也就是移位的次数
visit.clear(); //多次输入一定要 clear,不然会影响下一次输入的结果
return;
}
string str;
for(int i = 0; i < len - 1; ++i){ //由题意知最多输入13个字符,那最多就有12种移位方式
Code next(current.s, current.m + 1); //定义一个结构体next表示当前状态的下一状态,注意区别就是移位次数 +1 了
if(i == 0){
str = swap(next.s, 0);
}
else if(i == 1){
str = swap(next.s, 1);
}
else if(i == 2){
str = swap(next.s, 2);
}
else if(i == 3){
str = swap(next.s, 3);
}
else if(i == 4){
str = swap(next.s, 4);
}
else if(i == 5){
str = swap(next.s, 5);
}
else if(i == 6){
str = swap(next.s, 6);
}
else if(i == 7){
str = swap(next.s, 7);
}
else if(i == 8){
str = swap(next.s, 8);
}
else if(i == 9){
str = swap(next.s, 9);
}
else if(i == 10){
str = swap(next.s, 10);
}
else if(i == 11){
str = swap(next.s, 11);
}
next.s = str;
if(visit[next.s] == true){ //判断当前的字符串是否出现过
continue; //出现过就不把当前字符串压入队列(无效状态)
}
Q.push(next); //没出现过把新的字符串压入队列(新的有效状态)
visit[next.s] = true; //新的字符串现在出现过了,map 中设为 true
}
}
visit.clear(); //多次输入一定一定要 clear,不然下面的输入输出结果永远是 -1
cout << "-1" << endl; //所有有效状态遍历完了,还是没有合格的,输出 -1
}
int main(){
int n;
string str;
while(cin >> n){
cin >> str;
BFS(str); //人生的第一个BFS,通过的瞬间好爽
}
return 0;
}
#include <bits/stdc++.h>
(755)#include <queue>
using namespace std;
int n;
map<string,bool>m;
typedef struct {
string s;
int depth;
} tree;
bool isTrue(tree str) {
for(int i=0; i<=n-4; i++) {
if(str.s.substr(i,4)=="2012") {
return true;
}
}
return false;
}
string ownswap(tree str,int x,int y ) {
char tmp=str.s[x];
str.s[x]=str.s[y];
str.s[y]=tmp;
return str.s;
}
int main() {
queue<tree>q;
//int flag=0;
tree str,tmp;
cin>>n>>str.s;
str.depth=0;
m[str.s]==true;
q.push(str);
while(!q.empty()) {
tmp=q.front();
if(isTrue(tmp)) {
cout<<tmp.depth<<endl;
break;
}
//flag++;
q.pop();
for(int i=0; i<n-1; i++) {
tree tmp1;
tmp1.s=ownswap(tmp,i,i+1);
tmp1.depth=tmp.depth+1;
if(m[tmp1.s]==true) continue;
else{
m[tmp1.s]=true;
q.push(tmp1);
}
}
}
return 0;
}
#include<iostream>
(720)#include<cstdio>
#include<map>
(747)#include<cstring>
#include<queue>
using namespace std;
map<string,int> visit;
int BFS(int n,string s){
queue<string> Q;
Q.push(s);
visit[s]=1;
while(!Q.empty()){
string temp=Q.front();
Q.pop();
if(temp.find("2012",0)!=string::npos)
return visit[temp]-1;
for(int i=0;i<n-1;i++){
string str=temp;
swap(str[i],str[i+1]);
if(visit[str]!=0) continue;
else{
Q.push(str);
visit[str]=visit[temp]+1;
}
}
}
return -1;
}
int main(){
int N;
string input;
while(scanf("%d",&N)!=EOF){
cin>>input;
printf("%d\n",BFS(N,input));
}
return 0;
}
自己写的,没有参考,应该比较清楚了吧
#include <bits/stdc++.h> using namespace std; struct code{ string code_str; int step; }; int getStep(string str,int n){ vector<code> vi; int index=0; //step代表当前字符串是交换了几次的结果,初始值为0,因为可能存在一开始就有2012 code c; c.step=0; c.code_str=str; vi.push_back(c); //初始化 //开始只想到了全排列,所以跳出的条件是 pow(3,n) 比如 长度为4的串,最多有 3的四次方个排列 . //看完讨论后才知道是BFS,哈哈 ,用队列比较好 while(vi.size()<pow(3,n)){ if(vi[index].code_str.find("2012")!=-1){ return vi[index].step; }else{ string tem; tem=vi[index].code_str; for(int i=0;i<n-1;i++){ //没找到 那么只能由当前的字符串交换一次后所有结果加进去,在加的时候顺便判读一下是否有了 2012 swap(tem[i],tem[i+1]); code next; next.code_str=tem; next.step=vi[index].step+1; if(tem.find("2012")!=-1){ // 在加的时候顺便判读一下是否有了 2012 return next.step; } vi.push_back(next); tem=vi[index].code_str; } index++; } } return -1; } int main(){ int n; string str; while(cin>>n>>str){ if(n<4){ cout<<-1<<endl; }else{ cout<<getStep(str,n)<<endl; } } return 0; }
/*
考察BFS
*/
#include <bits/stdc++.h>
using namespace std;
map<string,int> visit; // 标记数组,并且还能还能表示交换次数
string swap(string str,int x,int y){ // 交换字符串x,y位置的字符
char temp = str[x];
str[x] = str[y];
str[y] = temp;
return str;
}
int BFS(string str){
visit.clear(); // 每次标记数组都要清0
queue<string> myQueue;
myQueue.push(str);
visit[str] = 0; // 第一次进来交换次数为0
while(!myQueue.empty()){ // 队列非空时才进行
string cur = myQueue.front();
myQueue.pop();
if(cur.find("2012")!=string::npos){ // 如果当前直接就找到了,那么直接返回
return visit[cur];
}else{
for(int i = 0;i<cur.size()-1;i++){
string temp = swap(cur,i,i+1);
if(visit.find(temp)==visit.end()){ // 如果不在标记中,即之前没有出现过,才入队
myQueue.push(temp);
visit[temp] = visit[cur]+1; // 交换次数是上一层的次数+1
}
}
}
}
return -1; // 走完所有可能都没有找到,返回-1
}
int main(){
int n; // n的意义不明
string str;
while(cin>>n>>str){
cout<<BFS(str)<<endl;
}
return 0;
}