【贪心算法】特殊的密码锁(openjudge8469)
a:特殊密码锁
- 总时间限制:
- 1000ms
- 内存限制:
- 1024kB
- 描述
-
有一种特殊的二进制密码锁,由n个相连的按钮组成(n<30),按钮有凹/凸两种状态,用手按按钮会改变其状态。
然而让人头疼的是,当你按一个按钮时,跟它相邻的两个按钮状态也会反转。当然,如果你按的是最左或者最右边的按钮,该按钮只会影响到跟它相邻的一个按钮。
当前密码锁状态已知,需要解决的问题是,你至少需要按多少次按钮,才能将密码锁转变为所期望的目标状态。
- 输入
- 两行,给出两个由0、1组成的等长字符串,表示当前/目标密码锁状态,其中0代表凹,1代表凸。
- 输出
- 至少需要进行的按按钮操作次数,如果无法实现转变,则输出impossible。
- 样例输入
-
011 000
- 样例输出
- 1
思路:看到输入输出首先想到的是枚举所有按钮的状态,但是n的范围为30,所以会有2的30次方多种,所以肯定不能枚举出所有状态,于是想了一个贪心策略,从左往右,如果按钮不匹配就按下一个按钮,始终让左面的按钮是匹配的,如果遍历到最后一个按钮不匹配则"impossible",否则输出最少的按钮次数。但是我忽略了一个特殊情况即前两个按钮,当前两个按钮不匹配时既可以按第一个按钮也可以按第二个按钮,所以应当考虑这两种情况最后哪中情况按的次数少。由于我写的代码比较复杂,所以找了个大佬的代码如下:
#include <iostream> #include <string> #include <algorithm> using namespace std; string s,t,fin; int tmp=0,ans=1e9,n; /*字符串中'1'与'0'的转换值得学习*/ inline void flip(int i){ s[i-1]=s[i-1]=='1'?'0':'1'; s[i]=s[i]=='1'?'0':'1'; if(i+1<n) s[i+1]=s[i+1]=='1'?'0':'1'; } int main(int argc, const char * argv[]) { cin>>s>>fin;t=s; n=s.size(); //第一种情况:按钮不匹配按后面的按钮 for(int i=1;i<n;i++) if(s[i-1]!=fin[i-1]){ flip(i); tmp++; } if(s[n-1]==fin[n-1]) ans=tmp; //第二种情况:如果前两个按钮不匹配,按第一个按钮,其他按钮不匹配还是按后一个按钮 tmp=1; s=t; //原作者没有加这个判断,加上判断代码更清晰一些。 if(s[0]!=fin[0]||s[1]!=fin[1]){ s[0]=s[0]=='1'?'0':'1'; s[1]=s[1]=='1'?'0':'1'; for(int i=1;i<n;i++) if(s[i-1]!=fin[i-1]){ flip(i); tmp++; } } //按完以后如果最后一个按钮相同,则输出两种情况中的按的次数最少的情况。 if(s[n-1]==fin[n-1]) ans=min(ans,tmp); //如果不同,则 if(ans==1e9) cout<<"impossible"; else cout<<ans; return 0; }
代码改自:http://www.cnblogs.com/candy99/p/5791488.html
祝你早日攒够失望,然后开始新的生活。