首页 > 技术文章 > UVa 12545 Bits Equalizer (贪心)

dwtfukgv 2016-06-06 00:30 原文

题意:给出两个等长的字符串,0可以变成1,?可以变成0和1,可以任意交换s中任意两个字符的位置,问从s变成t至少需要多少次操作。

析:先说我的思路,我看到这应该是贪心,首先,如果先判断s能不能变成t,就计算t中的1和s中的1。

然后算出t比s多多少1,然后先考虑把?变成1是最优的,如果不够就只能把0变成1,切不可把?变成1,因为这样要两步,

不是最优,而把0变成1是一步。然后把剩下的?变成1(如果1还不够)或者是0(1够了)。最后是计算要交换的次数,

这个只要统计不同的位置有多少即可,别忘了1可能还不够,这个也要算上,怎么算呢,想一下,先把0变成1,再交换,

所以说是要先加上要变化的1,然后在不同位置中也加上,然后除以2.相加就是结果。

然而我觉得自己写的太烂了,上网百度,看到大神们写的就是简洁明了。。。。

是这么想的,首先交换是最优的,因为一次操作能满足两个,然后再去找1-0和?-1的进行交换,为什么呢?因为我们看s中的1是不是多了,

如果少,没关系,可以直接把?变成1,如果多了就无解了,所以要比较这个。最后再加上?-0即可,这个只要一步。

大神就是牛逼。

代码如下:

这是我的代码

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
const int maxn = 100 + 10;
char s[maxn], t[maxn];

int main(){
//    freopen("in.txt", "r", stdin);
    int T;    cin >> T;
    for(int kase = 1; kase <= T; ++kase){
        scanf("%s %s", s, t);
        int n = strlen(s);
        int cnts1 = 0, cntt0 = 0, cnts0 = 0;//cnts1是s串中1的个数,同理其他的
        for(int i = 0; i < n; ++i){
            if('0' == t[i])   ++cntt0;
            if('0' == s[i])   ++cnts0;
            else if('1' == s[i])  ++cnts1;
        }
        int cntt1 = n - cntt0;//1的个数
        int cntss = n - cnts0 - cnts1;//?的个数
        int det = cntt1 - cnts1;//s和t差多少1

        printf("Case %d: ", kase);
        if(det < 0){  printf("-1\n"); continue; }//1太多了,把问号全改了都不够

        int cnt = 0;
        for(int i = 0; i < n; ++i)
            if(det && '?' == s[i] && t[i] == '1'){
                ++cnt;  s[i] = '1'; --det;//把?变成1
            }

        for(int i = 0; i < n; ++i)//把0变成1
            if(det && '0' == s[i] && '1' == t[i]){
                --det;  s[i] = '1';  ++cnt;
            }

        for(int i = 0; i < n; ++i){//把剩下的?变成0或1
            if(det && '?' == s[i]){  ++cnt;  s[i] = '1';  --det; }
            if(!det && '?' == s[i]){  ++cnt;  s[i] = '0';  }
        }

        int x = 0;
        for(int i = 0; i < n; ++i)//计算不同的数,
            if(s[i] != t[i]) ++x;

        cnt += det;//计算要要交换的次数
        cnt += (x + det)/ 2;
        printf("%d\n", cnt);
    }
    return 0;
}

 

下面是我参考大神们的代码写的:

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;
const int maxn = 100 + 10;
char s[maxn], t[maxn];

int main(){
    int T;    cin >> T;
    for(int kase = 1; kase <= T; ++kase){
        scanf("%s %s", s, t);
        int n = strlen(s);
        int zero_one = 0, one_zero = 0, q_one = 0, q_zero = 0;

        for(int i = 0; i < n; ++i){
            if(s[i] == '0' && t[i] == '1')  ++zero_one;
            else if(s[i] == '1' && t[i] == '0')  ++one_zero;
            else if(s[i] == '?' && t[i] == '0')  ++q_zero;
            else if(s[i] == '?' && t[i] == '1')  ++q_one;
        }

        int cnt = 0;
        while(zero_one && one_zero){
            --zero_one;   --one_zero;
            ++cnt;
        }

        while(q_one && one_zero){
            --q_one;   --one_zero;
            cnt += 2;
        }

        if(one_zero)  cnt = -1;
        else  cnt += q_zero + zero_one + q_one;

        printf("Case %d: %d\n", kase, cnt);
    }
    return 0;
}

 

推荐阅读