题目描述
玛雅人有一种密码,如果字符串中出现连续的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
解题思路:
主要考察BFS的思想,将走一步的情况作为树的第一层,依次类推,按层遍历。
# include <stdio.h>
# include<queue>
# include<string.h>
using namespace std;
# define N 13
struct str
{
char ch[N];
int step;
};
queue<str> Q;
bool is_ok(char *a)
{
int j=0;
for(j=0;j<strlen(a)-3;j++)
{
if(a[j]=='2'&&a[j+1]=='0'&&a[j+2]=='1'&&a[j+3]=='2')
return true;
}
return false;
}
int BFS(int n)
{
while(Q.empty()==false)
{
int i=0;
str now;
now=Q.front();
Q.pop();
if(is_ok(now.ch))
{
return now.step;
}
now.step++;
for(i=1;i<n;i++)//保证同一层内的节点对应的step相同
{
str tmp;
strcpy(tmp.ch,now.ch);
char tmpCh=tmp.ch[i];
tmp.ch[i]=tmp.ch[i-1];
tmp.ch[i-1]=tmpCh;
tmp.step=now.step;
if(tmp.step>n)//最多n步,再不结束就一定不满足题意,比较野蛮的结束方式。其实最好是设一个标记。
{
return -1;
}
else{
if(is_ok(tmp.ch))
{
return tmp.step;
}
Q.push(tmp);
}
}
}
return -1;
}
int main()
{
int n;
int i;
char input[N];
int cnt[3];
str S;
while(scanf("%d",&n)!=EOF)
{
//初始化
memset(input,0,sizeof(input[0]));
memset(cnt,0,sizeof(cnt));
if(Q.empty()==false)
Q.pop();
S.step=0;
//输入
scanf("%s",input);
for(i=0;i<n;i++)
{
cnt[input[i]-'0']++;
}
if(cnt[0]<1||cnt[1]<1||cnt[2]<2)//不满足2012这个字符串的基本条件,进入下一次循环
{
printf("-1\n");
continue;
}
strcpy(S.ch,input);//记录此时的状态
Q.push(S);
int ans=BFS(n);
printf("%d\n",ans);
}
return 0;
}
改进版:
原来大家都用hash的思想来给每个字符串打标签。
参考自:这位博主~
# include <stdio.h>
# include<queue>
# include<string.h>
using namespace std;
# define N 13
struct str
{
char ch[N];
int num;
int step;
//由于只涉及到012,转换为3进制,方便最后打标签
void change()
{
num=0;
int i,j;
for(i=0,j=1;i<N;i++,j*=3)
num+=(ch[i]-'0')*j;
}
};
bool mark[1600000];//给每个进入的值打标签,遍历之后不再遍历,但是这里的mark需要很大,不然会越界。
queue<str> Q;
bool is_ok(char *a)
{
int j=0;
for(j=0;j<strlen(a)-3;j++)
{
if(a[j]=='2'&&a[j+1]=='0'&&a[j+2]=='1'&&a[j+3]=='2')
return true;
}
return false;
}
int BFS(int n)
{
while(Q.empty()==false)
{
int i=0;
str now;
now=Q.front();
Q.pop();
now.step++;
for(i=1;i<n;i++)//保证同一层内的节点对应的step相同
{
str tmp;
strcpy(tmp.ch,now.ch);
char tmpCh=tmp.ch[i];
tmp.ch[i]=tmp.ch[i-1];
tmp.ch[i-1]=tmpCh;
tmp.change();
tmp.step=now.step;
if(mark[tmp.num]==true)
continue;
if(is_ok(tmp.ch))
{
return tmp.step;
}
mark[tmp.num]=true;
Q.push(tmp);
}
}
return -1;
}
int main()
{
int n;
int i;
char input[N];
int cnt[3];
str S;
while(scanf("%d",&n)!=EOF)
{
//初始化
memset(input,0,sizeof(input[0]));
memset(cnt,0,sizeof(cnt[0]));
memset(mark,0,sizeof(mark[0]));
if(Q.empty()==false)
Q.pop();
S.step=0;
//输入
scanf("%s",input);
for(i=0;i<n;i++)
{
cnt[input[i]-'0']++;
}
if(cnt[0]<1||cnt[1]<1||cnt[2]<2)//不满足2012这个字符串的基本条件,进入下一次循环
{
printf("-1\n");
continue;
}
strcpy(S.ch,input);//记录此时的状态
S.change();
mark[S.num]=true;
Q.push(S);
if(is_ok(S.ch))
{
printf("%d\n",S.step);
continue;
}
int ans=BFS(n);
printf("%d\n",ans);
}
return 0;
}