【贪心算法】特殊的密码锁(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

posted @ 2017-07-11 10:09  路人姜。  阅读(3737)  评论(0编辑  收藏  举报