题目描述
咳咳咳咳,这题还没大佬来发题解 我来混一波,思路在下面会有,嘻嘻嘻嘻~~~~。
是这样的,题目的*我都用中文代替了,原因是因为两个星号被认为是加粗字体,所以说没有办法正常显示题目,换成中文也是不错滴0.0。
小明正在玩一个“翻硬币”的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:星星oo星星oooo
如果同时翻转左边的两个硬币,则变为:oooo星星星oooo
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
样例
**********
o****o****
输出
5
算法思路
我们可以这样思考这个题目,我们如何使翻硬币次数最少就能达到最高目的呢?
不妨假设我们随便翻,如果这样,我们每改变一个位置的硬币,都会影响周围两个硬币的状态,且只能影响其中一个(要么前面的,要么后面的),这样话我们即使使用暴力枚举完成也无法保证其次数最少,怎么办让它次数最少呢?
很简单,我们每翻一个硬币就把他的状态固定下来,类似于费解的开关的题目,每一层灯的状态只能被下一层所更改,且保证上一层等都是亮的,这个题目也是类似的思想,我每翻一个硬币,就保证前面的硬币和目标硬币状态一样的,这样的话次数就最少了.........
仔细思考上面的思路,并不难理解,想明白上面的大体思路我们再来看怎样去翻,假设第二个位置和第三个位置不同,我怎么去翻,我一定要去翻第三个硬币来去影响第二个硬币,也可以理解为如果当前判断的硬币状态与目标硬币状态不同,我就翻当前状态的硬币,和下一个硬币,为什么要这样呢,为啥第二个位置不同就不能翻第二个硬币和第一个硬币呢?我前面说了,一定要保证翻过的硬币状态就和目标状态相同,也就是说,我在判断第一个硬币状态的时候就已经将第一个硬币状态确定下来了,第二个硬币无论如何不能影响第一个硬币,即我们在翻任何一个与目标硬币不相同的硬币时,只能翻下一个硬币,而不能翻前面的硬币,这个思路应该还是不难理解的.....
,,,看代码吧
时间复杂度
O(a.length());
大约是这样吧,内层循环被if条件限制了,这个复杂度应该是最优的,即目标硬币和输入硬币完全相同。
C++ 代码
#include<bits/stdc++.h> //万能头文件,,,偷个懒 嘻嘻
using namespace std;
string a,b;
int ans;
int main(){
cin>>a>>b;
for(int i=0;i<a.length();i++){
if(b[i]==a[i]){ //如果目标状态和输入状态相同,跳过即可
continue;
}
else{
for(int j=i;j<=i+1;j++){ //更新当前硬币状态和下一个硬币状态
if(a[j]=='o') a[j]='*';
else a[j]='o';
}
ans++; //答案+1
}
}
cout<<ans<<endl;//华丽的输出0.0
return 0;
}
吓得我赶紧去打卡,,,,,如有错误,请及时批评,新手题解,望支持~
谢谢>....<~
写一个更利于理解看法,证明这个做法是最优的
如同y总在基础课讲贪心的证明一样
设我们当前的做法得到的翻转次数是cnt,最优做法得到的最小翻转次数是ans
并且先假设这两种方法不同(不然ans就默认等于cnt了…)
显然我们要证明 cnt >= ans && cnt <= ans
由于这个做法是可达到目的的,所以cnt >= ans ..............................<1>
下面证明ans >= cnt
对于转换中的某一个状态,我们从左到右找到第一个与目标状态不同的硬币
设其位置是x。要改变x,只有两种方法,即翻转x - 1和x(设为方法1),或者翻转x和x + 1(设为方法2)
由于x是从左到右第一个与目标状态不同的硬币,如果我们用前者的翻转方式,
那么它还要对 0~x-1这一段再做处理。下面好戏来了,各位坐稳扶好
因为0~x-1中只有一个硬币与目标状态不同,即第x-1个硬币,事实上在处理这一段时
我们无论如何都不能使它变成目标状态。要想处理它,必须翻转x-1和x
这样我们就又回到了原来的状态(各位画个图很容易理解)
因此这种做法进行了两次翻转但是并没有引起状态的改变
所以它翻转的次数必定比方法2多
最终,由于我们假设最优的做法跟我们所用的做法是不同的,那么它在翻转过程中必定使用了方法1
所以最后得到的ans必定 >= cnt。
因此
ans >= cnt .................................<2>
综上<1><2>我们有ans = cnt
醍醐灌顶
讲的真好
这是学到了真东西了
时间复杂度应该是两倍的a.length()吧,因为每次都要翻两个硬币
对 但常数通常会就不计了
好的谢谢
感谢、题解写的很棒!
感谢!
up++