您的位置:首页 > 编程语言 > Go语言

Google Code Jam 2016 Round 1B B

2016-05-27 09:12 309 查看
题意:给出两个数字位数相同,分别中间有若干位不知道,用问号表示。现在要求补全这两个数字,使得差值的绝对值最小,多解则取第一个数字的值最小的,再多解就取第二个数字最小的。

分析:

类似数位dp,但是很多状态可以直接得出最终解,个别状态需要状态转移。

我们从高位到低位依次确定两个数的每个位是几。一旦确定了两个数的一个位不一样,则可以立即将小的一方的后续问号全部写9,大的一方后续问号全部写0。这样才能让差值最小。

那我们观察每个位的时候要如何确定其值呢?分如下几种情况。

1.两个数的该位都是问号,那么分三种情况:

  1.1 都标为0,看下一个位。

  1.2&1.3 将一位标为1,另一个位标为0,并更新答案,终结状态。(这表示我们主动在高位制造了一个差值以便后面取得整体差值最小。例如:?0?,?9?,答案是100,099)

2.两个数的该位都不是问号,若相等,继续看下一位。若不等,则标出后面问号,更新答案,终结状态。

3.两个数的该位有一个是问号,那么这个这与第一种情况类似,分三种情况处理。

  3.1 标为与该位相等,看下一个位。

  3.2 标为该位减1,赋值后续问号,更新答案,终结状态。

  3.3 标为该位加1,赋值后续问号,更新答案,终结状态。

就这么多情况。值得注意的是,虽然有些时候进行了状态转移(看下一个位)。但是并不需要搜索和回溯。因为每个状态的多个分支中,只有一个是状态转移,其他的都是最终态。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;

#define d(x)

const int MAX_LEN = 20;

char st[2][MAX_LEN];
char ans[2][MAX_LEN];
char temp[2][MAX_LEN];
long long diff;
int n;

void input()
{
scanf("%s", st[0]);
scanf("%s", st[1]);
n = strlen(st[0]);
}

long long get_value(char st[])
{
long long ten = 1;
long long ret = 0;
for (int i = n - 1; i >= 0; i--)
{
ret += (st[i] - '0') * ten;
ten *= 10;
}
return ret;
}

bool ok(long long temp_diff)
{
if (temp_diff > diff)
return false;
if (temp_diff < diff)
return true;
if (strcmp(ans[0], temp[0]) > 0)
return true;
if (strcmp(ans[0], temp[0]) < 0)
return false;
return strcmp(ans[1], temp[1]) > 0;

}

void update()
{
long long a = get_value(temp[0]);
long long b = get_value(temp[1]);
long long temp_diff = abs(a - b);
if (ok(temp_diff))
{
diff = temp_diff;
strcpy(ans[0], temp[0]);
strcpy(ans[1], temp[1]);
}
}

void make(int index, int a, int b)
{
if (a < 0 || b < 0 || a > 9 || b > 9)
return;

strcpy(temp[0], st[0]);
strcpy(temp[1], st[1]);

temp[0][index] = a + '0';
temp[1][index] = b + '0';

int ch_a = '9';
int ch_b = '0';
if (a > b)
swap(ch_a, ch_b);
for (int i = index + 1; i < n; i++)
{
if (temp[0][i] == '?')
temp[0][i] = ch_a;
if (temp[1][i] == '?')
temp[1][i] = ch_b;
}
d(printf("a=%d\n", a));
d(printf("b=%d\n", b));
d(puts(temp[0]));
d(puts(temp[1]));
update();
}

void work()
{
diff = 1LL << 62;
for (int i = 0; st[0][i]; i++)
{
if (st[0][i] == st[1][i] && st[0][i] != '?')
{
continue;
}
if (st[0][i] == st[1][i] && st[0][i] == '?')
{
make(i, 0, 1);
make(i, 1, 0);
st[0][i] = st[1][i] = '0';
continue;
}
//reach here means st[0][i] != st[1][i]
if (st[0][i] != '?' && st[1][i] != '?')
{
make(i, st[0][i] - '0', st[1][i] - '0');
return;
}
//reach here means only one of them is ?.
if (st[0][i] == '?')
{
make(i, st[1][i] - '0' + 1, st[1][i] - '0');
make(i, st[1][i] - '0' - 1, st[1][i] - '0');
st[0][i] = st[1][i];
}
if (st[1][i] == '?')
{
make(i, st[0][i] - '0', st[0][i] - '0' + 1);
make(i, st[0][i] - '0', st[0][i] - '0' - 1);
st[1][i] = st[0][i];
}

}
make(n - 1, st[0][n - 1] - '0', st[1][n - 1] - '0');
}

int main()
{
int t;
scanf("%d", &t);
int case_num = 0;
while (t--)
{
case_num++;
printf("Case #%d: ", case_num);
input();
work();
printf("%s %s\n", ans[0], ans[1]);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: