清华大学考研复试机试:密码锁

版权声明:本文为博主原创,未经博主允许不得转载。转载请附上原文链接。 https://blog.csdn.net/qq_38341682/article/details/88640311

题目描述

玛雅人有一种密码,如果字符串中出现连续的2012四个数字就能解开密码。给一个长度为N的字符串(2=<N<=13),该字符串中只含有0,1,2三种数字,问这个字符串要移位几次才能解开密码,每次只能移动相邻的两个数字。例如02120经过一次移位,可以得到20120,01220,02210,02102,其中20120符合要求,因此输出为1.如果无论移位多少次都解不开密码,输出-1。

输入描述

第一行输入N,第二行输入N个数字,只包含0,1,2

输出描述

示例:

输入

5
02120
5
02120

输出

1
1

分析

博主之前有一篇“玛雅人的密码”文章,这道题与那道题是一样的,故这里只是提一下简单的思路,具体的分析读者可以参考博主之前的文章。

这道题可以使用BFS搜索来做,使用STL的queue作为搜索队列,使用map记录每一个新的字符串需要经过多少次转换。另外需要写一个字符串移位的函数,每次只移动一位,每次移位后都需要判断是否符合题意。若不符合题意,将新的字符串放入队列中,直到队列为空。另外,只有一种情况会输出-1,就是数字不够的时候,这需要在输入的时候就进行判断。最后,在输出时一定要注意格式,每一个输出后都需要换行,不然会返回答案错误。

AC代码如下:

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

using namespace std;

map<string, int> msi;
queue<string> que;

int possible(string str)//判断是否有解
{
	int c[3] = {0};
	int length = str.length();
	for(int i = 0; i < length; ++i)
	{
		//记录字符0,1,2的个数,这个技巧很常见,需要掌握
		++c[str[i]-'0'];
	}
	//数字不够是导致这道题无解的唯一原因
	if(c[0] == 0 || c[1] == 0 || c[2] < 2)
	{
		return -1;
	}
	return 0;
}

bool judge(string str)//判断是否是解
{
	if(str.find("2012") == -1)//字符串中不包含目标子串
	{
		return false;
	}
	return true;
}

string myswap(string str, int i)//字符移位
{
	string temp = str;
	temp[i] = str[i+1];
	temp[i+1] = str[i];
	return temp;
}

int main(void)
{
	int n;
L:	while(cin >> n)//标号用于goto跳出多重循环
	{
		string str;
		cin >> str;
		if(possible(str) == -1)//首先判断是否有解
		{
			cout << -1 << endl;
		}
		else
		{
			msi.clear();//将map清空
			//STL的queue没有提供clear方法,不过我们应该有很多方法清空一个队列
			//这个方法应该是清空队列最快的方法
			//将非空队列和空队列进行交换,利用了泛型swap方法
			queue<string> empty;
			swap(empty, que);
			que.push(str);//将原始字符串压入队列
			msi[str] = 0;//map记录移位次数,这种语法也可以在map中插入元素
			string temp;
			while(!que.empty())//队列非空
			{
				temp = que.front();//取出队列首元素的方法是front
				que.pop();//将队列首元素移除
				if(judge(temp))//判断是否符合条件
				{
					cout << msi[temp] << endl;
					break;//进入下一个输入
				}
				else//不符合条件
				{
					string newstr;
					for(int i = 0; i < n-1; ++i)//不断移位
					{
						newstr = myswap(temp, i);
						if(msi.find(newstr) != msi.end())//不是新字符串
						{
							if(judge(newstr))//判断是否符合条件
							{
								cout << msi[newstr] << endl;
								goto L;//进入下一个输入
							}
						}
						else//是新字符串
						{
							//在map中插入新元素,并且移位次数加1
							msi[newstr] = msi[temp] + 1;
							if(judge(newstr))//判断是否符合条件
							{
								cout << msi[newstr] << endl;
								goto L;//进入下一个输入
							}
							else//不符合条件的新字符串就压入队列中
							{
								que.push(newstr);
							}
						}
					}
				}
			}
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38341682/article/details/88640311