Google Code Jam 2016 Round 1B B

題意:給出兩個數字位數相同,分別中間有若干位不知道,用問號表示。如今要求補全這兩個數字,使得差值的絕對值最小,多解則取第一個數字的值最小的,再多解就取第二個數字最小的。ide

分析:spa

相似數位dp,可是不少狀態能夠直接得出最終解,個別狀態須要狀態轉移。code

咱們從高位到低位依次肯定兩個數的每一個位是幾。一旦肯定了兩個數的一個位不同,則能夠當即將小的一方的後續問號所有寫9,大的一方後續問號所有寫0。這樣才能讓差值最小。blog

那咱們觀察每一個位的時候要如何肯定其值呢?分以下幾種狀況。get

1.兩個數的該位都是問號,那麼分三種狀況:input

  1.1 都標爲0,看下一個位。string

  1.2&1.3 將一位標爲1,另外一個位標爲0,並更新答案,終結狀態。(這表示咱們主動在高位製造了一個差值以便後面取得總體差值最小。例如:?0?,?9?,答案是100,099)it

2.兩個數的該位都不是問號,若相等,繼續看下一位。若不等,則標出後面問號,更新答案,終結狀態。io

3.兩個數的該位有一個是問號,那麼這個這與第一種狀況相似,分三種狀況處理。event

  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
相關文章
相關標籤/搜索