P1-2017級第一次演算法上機 E 位元手鍊
阿新 • • 發佈:2018-12-23
題目描述
葉姐要想哥贈送一串位元手鍊,這個手鍊由0和1組成。想哥買了手鍊B,無意間得知葉姐想要同樣長度的手鍊A。想哥囊中羞澀,只能手工調整手鍊。他希望最少通過以下操作進行最少步驟把B變成A。注意:A != B
對於一個串S:
操作1——選擇下標i,j,i != j:
·result = S[i] & S[j]
·S[i] = result & S[i]
·S[j] = result & S[j]
操作2——選擇下標i,j,i != j:
·result = S[i] | S[j]
·S[i] = result | S[i]
·S[j] = result | S[j]
操作3——選擇下標i,j,i != j:
·result = S[i] ^ S[j]
·S[i] = result ^ S[i]
·S[j] = result ^ S[j]
問想哥最少多少步能達成心願。如果想哥無法達成心願,輸出-1。
輸入
第一個數為資料組數T
接下來2T行,第2i - 1行為手鍊B,第2i行為手鍊A
輸出
對於每組資料,輸出一行,最少的步驟數。特別地,如果無法達成,輸出-1。
輸入樣例
2
101
010
1111
1010
輸出樣例
2
-1
Hint
T<=5;
長度<=10^6;
思路
碰到這種型別,一般都要先手動模擬,尋找規律。
通過手動計算可以發現,若a[i] == a[j],則三個運算均不會造成影響;只有a[i] != a[j]時,即一個為0一個為1,才會造成改變。
對於&:相當與把1變成0;對於|:相當於把0變成1;對於^,相當於交換。
所以,如果原串全為0或全為1,由於A!=B,所以是無解的;否則解的個數即為max(0變成1的數量,1變成0的數量),也就是說,儘量使用^交換一次性解決兩個,無法交換了再用&或|一次修改一個。
參考程式碼
1 //我的版本 2 #include<stdio.h> 3 #include<string.h> 4 #define MAXN 1000002 5 int main() 6 { 7 int T;//資料組數 8 scanf("%d",&T); 9 while(T--){ 10 char b[MAXN],a[MAXN]; 11 scanf("%s%s",b,a); 12 int i,ans_b0 = 0; 13 int len = strlen(b); 14 int t01 = 0,t10 = 0; 15 for(i = 0;i < len;i++){ 16 if(b[i] == '0') 17 ans_b0++; 18 if(b[i] == '0' && a[i] == '1') 19 t01++; 20 if(b[i] == '1' && a[i] == '0') 21 t10++; 22 } 23 if(ans_b0 == len || ans_b0 == 0){ 24 printf("-1\n"); 25 continue; 26 } 27 printf("%d\n",Max(t01,t10)); 28 } 29 30 return 0; 31 } 32 33 int Max(int a,int b) 34 { 35 return a > b ? a : b; 36 }
1 //助教的版本 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 6 const int N=1000010; 7 int len,l,r,t,sum; 8 char a[N],b[N]; 9 10 inline int max(int a,int b) { 11 return a>b?a:b; 12 } 13 14 int main() { 15 for(scanf("%d",&t);t--;l=r=sum=0) { 16 scanf("%s%s",a,b); 17 len=std::strlen(a); 18 for(int i=0;i<len;++i) sum+=a[i]-'0'; 19 if(sum==0 || sum==len) { 20 puts("-1"); 21 continue; 22 } 23 for(int i=0;i<len;++i) 24 if(a[i]!=b[i]) 25 a[i]=='0' ? ++l : ++r; 26 printf("%d\n",max(l,r)); 27 } 28 return 0; 29 }