思路
设n0,n1,n2分别为s中与t不同的0、1、?数量,设n11为t中与s不同的1的数量
- 遍历s和t一遍得到上述变量值
- 若n1>n11无解
- 否则,解等于max(n0,n1)+n2。理由如下:
(以下讨论的都是s中的n0,n1和n2的数量)
- 贪心:交换操作一次改变两个位置,故先进行交换,则次数为min(n0,n1)
- 剩下n2和交换时多出来的部分n0,称n0余(或n1,称n1余),没有n1(或没有n0)
- n0余情况:反转0为1,问号根据t变0或1,次数为n0余+n2;n1补情况:交换1和问号,被交换的问号变0,未交换的根据t变0或1,次数为n1余+n2
- 由于n0余对应步骤1,min取n1情况,此时n0余+min(n0,n1)=n0;n1余情况同理。
- 步骤4即max(n0,n1),加上问号n2,即为解
AC代码
#include <iostream>
#include <cstring>
using namespace std;
const int maxl=105;
char s[maxl],t[maxl];
//#define TEST
int main(){
#ifdef TEST
freopen("D:\\college\\clionworkplace\\test_c++2\\in.txt","r",stdin);
freopen("D:\\college\\clionworkplace\\test_c++2\\out.txt","w",stdout);
#endif
int T;
scanf("%d",&T);
int kase=1;
getchar();
while (T--){
memset(s,0,sizeof(s));
memset(t,0, sizeof(t));
scanf("%s%s",s,t);
int n0=0,n1=0,n2=0,n11=0;
int ans=0;
for (int i = 0;; ++i) {
if(s[i]=='\0') break;
if(s[i]!=t[i]){
switch (s[i]) {
case'?':++n2;break;
case '1':++n1;break;
case '0':++n0;break;
}
if(t[i]=='1') ++n11;
}
}
if(n0==0 && n1==0 && n2==0) ans=0;
else if(n1>n11) {
ans = -1;
}else{
ans+=max(n0,n1);
ans+=n2;
}
printf("Case %d: %d\n",kase++,ans);
}
return 0;
}