桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:oo*oooo
如果同时翻转左边的两个硬币,则变为:oooo***oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
输入格式
两行等长的字符串,分别表示初始状态和要达到的目标状态。
输出格式
一个整数,表示最小操作步数
数据范围
输入字符串的长度均不超过100。
数据保证答案一定有解。
输入样例:
ooo***
ooo***
输出样例:
1
第一:广搜,但会超内存
//基本思想:队列保存所有翻转一次/两次/三次。。。。可以转变成的情况,
#include <iostream>
#include <queue>
using namespace std;
string s1;
string s2;
typedef struct f {
string s;
int step;
}sq;
queue<f>qu;
int main(void)
{
cin >> s1 >> s2;
sq a;
a.s = s1;
a.step = 0;
qu.push(a);
int k = 0;
while (!qu.empty())
{
sq str1 = qu.front();
qu.pop();
for (int i = 0; i < str1.s.size()-1; i++)
{
sq str = str1;
if (str.s[i] == '*')str.s[i] = 'o';
else if (str.s[i] == 'o')str.s[i] = '*';
if (str.s[i+1] == '*')str.s[i+1] = 'o';
else if (str.s[i+1] == 'o')str.s[i+1] = '*';
str.step = str1.step + 1;
if (str.s == s2)
{
cout << str.step;
k = 1;
return 0;
}
qu.push(str);
}
}
}
第二:朴素的算法
只需遍历一遍初始硬币样式,只要发现和目标硬币样式不一样,反转相邻两个硬币即可,因为如果初始第一位和目标第一位不一样,那么第一位是一定需要进行翻转的,往后遍历即可。
#include <iostream>
using namespace std;
string s1, s2;
int sum;
int main(void)
{
cin >> s1 >> s2;
//遍历过程中,s[i]前面的一定是和目标样式一样的,所以如果s1[i]和s2[i]
//不一样,那么只能翻动s1[i]和s1[i+1],遍历一遍即可
for (int i = 0; i < s1.size(); i++)
{
if (s1[i] != s2[i])//如果发现不一样了,0
{
if (i != s1.size() - 1)//遍历到最后一位时需要特殊判断 AX
{
if (s1[i] == '*')s1[i] = 'o';
else if (s1[i] == 'o')s1[i] = '*';
if (s1[i + 1] == '*')s1[i + 1] = 'o';
else if (s1[i + 1] == 'o')s1[i + 1] = '*';
}
else
{
if (s1[i] == '*')s1[i] = 'o';
else if (s1[i] == 'o')s1[i] = '*';
if (s1[i - 1] == '*')s1[i - 1] = 'o';
else if (s1[i - 1] == 'o')s1[i - 1] = '*';
}
sum++;
}
if (s1 == s2)
{
cout << sum << endl;
break;
}
}
return 0;
}