openJudge 特殊密碼鎖 ACM
- 總時間限制:
- 1000ms
- 記憶體限制:
- 1024kB
- 描述
-
有一種特殊的二進位制密碼鎖,由n個相連的按鈕組成(n<30),按鈕有凹/凸兩種狀態,用手按按鈕會改變其狀態。
然而讓人頭疼的是,當你按一個按鈕時,跟它相鄰的兩個按鈕狀態也會反轉。當然,如果你按的是最左或者最右邊的按鈕,該按鈕只會影響到跟它相鄰的一個按鈕。
當前密碼鎖狀態已知,需要解決的問題是,你至少需要按多少次按鈕,才能將密碼鎖轉變為所期望的目標狀態。
- 輸入
- 兩行,給出兩個由0、1組成的等長字串,表示當前/目標密碼鎖狀態,其中0代表凹,1代表凸。
- 輸出
- 至少需要進行的按按鈕操作次數,如果無法實現轉變,則輸出impossible。
- 樣例輸入
-
011 000
樣例輸出
-
1
首先先附上我AC的程式碼:
#include<iostream> #include<cstring> using namespace std; void change(char &a) { if(a=='0') a='1'; else if(a=='1') a='0'; else return ; } int main() { char a1[33],a2[33],b[33]; cin>>a1; cin>>b; int n=strlen(a1); strcpy(a2,a1); int sum1=1,sum2=0; change(a1[0]); change(a1[1]); for(int i=0;i<n-1;i++) //假設第一次按了第一個鍵 { int j=i; if(a1[i]!=b[i]) { sum1+=1; change(a1[++j]); change(a1[++j]); } } if(a1[n-1]!=b[n-1]) sum1=-1; for(int i=0;i<n-1;i++) //假設第一次未按第一個鍵 { int j=i; if(a2[i]!=b[i]) { sum2+=1; change(a2[++j]); change(a2[++j]); } } if(a2[n-1]!=b[n-1]) sum2=-1; if(sum1 ==sum2 && sum1 == -1) // 執行判斷 cout<<"impossible"; else { if(sum1 == -1 || sum2 == -1) cout<<(sum1 > sum2 ? sum1 : sum2); else cout<<(sum1 < sum2 ? sum1 : sum2); } }
然後講一下我做這題的思路。因為題目中描述按一個鍵改變自身和相鄰的鍵。列舉的時間複雜度太高,肯定是TLE,所以我採用的是貪心演算法,保證前面的鍵先全部符合,再去看能否讓最後一個鍵匹配到,如果匹配就表示可行,輸出改變的次數sum。
用for迴圈的模式判斷a[i]與b[i]是否能對應,能對應就繼續。不能對應就改變a[i]後兩個鍵,這樣的做法相當於按了a[i+1],不用考慮a[i]本身的原因是直接i++就能跳過對a[i]的判斷。
然後提交。
WA。
回去看了下程式碼,發現確實少考慮了一個情況。a[0]在題目中有特殊的地位——按下a[0]時僅改變之後的一個鍵,而改變a[0]的方法有兩種,一種是按a[0],另一種是按a[1],這兩種方法都不會影響之前陣列的匹配。甚至說是先按a[0]、再按a[1]都能使a[0]保持原樣而影響之後的陣列,所以不論a[0]與b[0]是否匹配,a[0]按和不按的情況都要考慮。
因此我把這種情況考慮進去。由於是change()是直接對陣列中的數修改,所以我另開一個數組儲存a,又另開一個sum統計變數。之後的判斷情況也進行了修改:如果第一次按了a[0],最後結果不能匹配則返回-1。
最後的輸出判斷也改成,如果兩個-1,那麼輸出impossible;哪個不是-1就輸出哪一個。(因為這兩種情況不會同時實現)
修改完以後提交。
成功AC。
-