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
