UVA 12545 Bits Equalizer 机智题

题目大意是给出两个串,第一个串由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];
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值