GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版
不难的题目。
注意变换只支持从0到1,不支持从1到0,因此如果s串中0的数量+问号的数量小于t串中0的数量,则说明无法成功,输出-1。
问号优先转换成对应位置的正确数字,这样步骤是最小的。但如果0不足,则需要将问号是1的位置变为0,补充0的数量。
所有问号处理完毕后,统计s串目前0但是应该为1和目前1但是应该为0的数量。两个数量相同的部分可以互换处理;不同的部分只能从0变1了(因为0肯定足够,所以不会有1转0)。因此步骤数直接加这两个数量的更大值即可, 不用真的去转换。
AC代码
cpp
#include <stdio.h>
#include <stdlib.h>
#define MAXN 105
char sArr[MAXN];
char tArr[MAXN];
int n;
int sZeroNum, sOneNum, sQuesNum;
int tZeroNum, tOneNum;
int judge()
{
int i;
sZeroNum = 0;
sOneNum = 0;
sQuesNum = 0;
tZeroNum = 0;
tOneNum = 0;
for (n = 0; tArr[n] != 0; ++n)
{
if (tArr[n] == '0')
++tZeroNum;
if (tArr[n] == '1')
++tOneNum;
}
for (i = 0; i < n; ++i)
{
if (sArr[i] == '0')
++sZeroNum;
if (sArr[i] == '1')
++sOneNum;
if (sArr[i] == '?')
++sQuesNum;
}
if (tZeroNum > sZeroNum + sQuesNum)
return false;
return true;
}
int computed()
{
int num = 0;
int i, j, k;
// 所有问号对应0的位置先赋值
for (i = 0; i < n; ++i)
{
if (sArr[i] != '?')
continue;
if (tArr[i] == '0')
{
sArr[i] = '0';
sQuesNum--;
sZeroNum++;
++num;
}
}
// 如果0依然不够,那就从1的位置补齐
for (i = 0; i < n; ++i)
{
if (sArr[i] != '?')
continue;
if (sZeroNum < tZeroNum)
{
sArr[i] = '0';
++sZeroNum;
}
else
{
sArr[i] = '1';
++sOneNum;
}
++num;
}
// 找出两者的不同的点,如果是0-1和0-1的不同可以交换,剩下的不同则只能变换
j = 0;
k = 0;
for (i = 0; i < n; ++i)
{
if (sArr[i] == '0' && tArr[i] == '1')
++j;
if (sArr[i] == '1' && tArr[i] == '0')
++k;
}
num += j > k ? j : k;
return num;
}
int main()
{
int t, i;
scanf("%d", &t);
for (int ti = 0; ti < t; ++ti)
{
scanf("%s", sArr);
scanf("%s", tArr);
printf("Case %d: ", ti + 1);
if (!judge())
{
printf("-1\n");
continue;
}
printf("%d\n", computed());
}
return 0;
}