Модифицированный динамический рюкзак - проблематичный вход?

Ниже приведена попытка решения этой проблемы SPOJ. Вход:

  1. Общий вес определенной суммы денег в монетах
  2. значения и соответствующие веса монет используемой валюты, и цель состоит в том, чтобы найти минимально возможную денежную стоимость данной суммы денег.

Я немного изменил решение задачи о рюкзаке с помощью динамического программирования из статьи в Википедии о задаче о рюкзаке. - Сначала я отсортировал монеты по весу, поэтому мне не нужно перебирать все монеты, чтобы получить наименьшее значение, и (надеюсь) убедился, что общий вес равен емкости. (Пожалуйста, посмотрите код, он очень простой и прокомментирован.)

Однако, по мнению судьи, есть ввод, для которого мой алгоритм дает неверный ответ. Подскажите, пожалуйста, что не так с алгоритмом?

#include <iostream>
#include <vector>
#include <algorithm>
#include <limits>

using namespace std;

typedef unsigned int weight_t;
typedef unsigned int value_t;

struct coin {
    weight_t weight;
    value_t value;
};

coin make_coin(weight_t weight, value_t value) {
    coin ret;
    ret.weight = weight;
    ret.value = value;
    return ret;
}

bool compare_by_weight(const coin& coin1, const coin& coin2) {
    return coin1.weight < coin2.weight;
}

int main() {
    unsigned int test_cases;
    cin >> test_cases;
    while(test_cases--) {
        //Initialization
        unsigned int number_of_coins, n = 0;
        weight_t empty_pig, full_pig, coin_weight, coins_weight;
        value_t coin_value, min_value, current_value = 0;
        vector<coin> coins;
        vector<unsigned int> min_value_for_the_weight;

        //Input
        cin >> empty_pig >> full_pig;
        cin >> number_of_coins;
        n = number_of_coins;
        while(n--) {
            cin >> coin_value >> coin_weight;
            coins.push_back(make_coin(coin_weight, coin_value));
        }

        //Input processing
        coins_weight = full_pig - empty_pig;
        sort(coins.begin(), coins.end(), compare_by_weight);
        min_value_for_the_weight.resize(coins_weight+1);
        for(unsigned int i = 0; i < coins_weight; i++) min_value_for_the_weight[i] = 0;

        //For all weights
        for(unsigned int i = 1; i <= coins_weight; i++) {
            //Find the smallest value
            min_value = numeric_limits<value_t>::max();
            for(unsigned int j = 0; j < number_of_coins; j++) {
                //The examined coin weights more or same than examined total weight and we either already have put a coin
                //in, or this is the first one
                if(coins[j].weight <= i && (min_value_for_the_weight[i - coins[j].weight] > 0 || i == coins[j].weight)){
                    current_value = coins[j].value + min_value_for_the_weight[i - coins[j].weight];
                    if(current_value < min_value) min_value = current_value;
                } else break;  // <- this I deleted to get accepted
            }
            if(min_value == numeric_limits<value_t>::max()) min_value = 0;
            min_value_for_the_weight[i] = min_value;
        }

        //If the piggy empty, output zero
        if(!min_value_for_the_weight[coins_weight] && coins_weight != 0)
            cout << "This is impossible." << endl;
        else
            cout << "The minimum amount of money in the piggy-bank is " << min_value_for_the_weight[coins_weight] << "." << endl;
        }
    return 0;
}

person mirgee    schedule 28.08.2014    source источник


Ответы (1)


Случай empty_pig == full_pig проблематичен, потому что вы забыли повторить логику в специальном регистре для нулевой записи min_value_for_the_weight.

Другая ошибка заключается в том, что это хорошая идея break только в том случае, если coins[j].weight > i. Старый код мог break, когда coin[j].weight <= i и другая половина конъюнкта были ложными, т. е. было невозможно сделать монеты весом i - coins[j].weight. Это происходит на следующем тестовом примере.

1
10 13
2
2 2
3 3

Мы должны сделать вес 3, используя монеты веса 2 или 3. Вес 1 правильно определяется как невозможный. Вес 2 правильно определен как возможный. Для веса 3 мы пробуем монету веса 2, определяем, что вес 1 невозможен, и break перед пробой монеты веса 3. В результате код ошибочно сообщает, что невозможно сделать вес 3.

person David Eisenstat    schedule 28.08.2014
comment
Спасибо! Итак, для пустой свиньи я вывожу минимальный вес 0. Но все равно с логикой что-то не так. (Я отредактировал сообщение, надеюсь, все в порядке.) - person mirgee; 29.08.2014
comment
Это было принято, если я удалил else break в логике. Можете ли вы объяснить, почему это привело к неправильным результатам? - person mirgee; 29.08.2014