题目大意是给出两个串,第一个串由0,1,?组成,第二个串由0和1组成,其中?能变成0或1,0能变成1,第一个串里面任意两个字符都可以交换。问从第一个串变到第二个串的最小步数。
实际上我一开始被题目的解决思路诱导了,导致在错误的地方尝试了好几次。
实际上这样考虑是最好的:
因为?的反正都可以变,因此放哪儿都无所谓,真正对我们有影响的是交换的这一步
首先,假若第一个串的1比第二个串的1多,肯定无解,因为1是不能变成其他的元素的。
其次,我们先尽可能的交换,让0和0匹配,1和1匹配,剩下的?只变换就好了。
那为了做到尽可能的交换,我们需要记录4个值(已经匹配的字符我们就不管了)
第二个串的0对应第一个串的1的数目,a
第二个串的0对应第一个串的?的数目,b
第二个串的1对应第一个串的0的数目,c
第二个串的1对应第一个串?的数目,d
首先,考虑a==c的情况,那么此时做a次交换,b+d次变换即达到要求,一共步数是a+b+d
然后考虑a>c的情况,首先说明a是不可能大于c+d的,不然就是无解
那么我们首先做a次交换(其中c次是和0交换,a-c次是和?交换),把1先尽可能的匹配好,此时串里还剩下b+d个问号待变换,因此一共的步数也是a+b+d
然后考虑a<c的情况
此时我们做a次交换,把1匹配好,此时串里还剩下b+d个问号,c-a个0等待变成1,所以一共的步数是a+c-a+b+d -> b+c+d
代码如下:
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
string str[2];
int n,kcase,arr[4];
bool judge();
/*
0 for 0 to 1
1 for 0 to ?
2 for 1 to 0
3 for 1 to ?
*/
int main(){
ios_base::sync_with_stdio(0);
cin>>n;
while(n--){
cin>>str[0]>>str[1];
cout<<"Case "<<++kcase<<": ";
if(judge())
cout<<-1<<endl;
else{
if(arr[0]==arr[2])
cout<<arr[0]+arr[1]+arr[3]<<endl;
else if(arr[0]>arr[2])
cout<<arr[0]+arr[1]+arr[3]<<endl;
else
cout<<arr[1]+arr[2]+arr[3]<<endl;
}
arr[0]=arr[1]=arr[2]=arr[3]=0;
}
return 0;
}
bool judge(){
int arr_b[2]{};
for(int i=0;i<str[0].size();++i){
if(str[0][i]=='1')++arr_b[0];
if(str[1][i]=='1')++arr_b[1];
if(str[1][i]=='0'&&str[0][i]=='1')++arr[0];
else if(str[1][i]=='0'&&str[0][i]=='?')++arr[1];
else if(str[1][i]=='1'&&str[0][i]=='0')++arr[2];
else if(str[1][i]=='1'&&str[0][i]=='?')++arr[3];
}
return arr_b[0]>arr_b[1];
}