Динамическое программирование - задача о рюкзаке 0/1

1. Описание проблемы

0/1 задача о рюкзаке 1
Ограничение по времени:  1000 мс Лимит памяти:  5000 КБ

Описание

Имеется рюкзак вместимостью C (C<=100) и N (N<=500) драгоценных камней, размер i-го драгоценного камня равен si, а стоимость равна vi. В силу условий,
У вас под рукой только этот рюкзак как единственный инструмент для перевозки драгоценных камней. Теперь вы хотите знать, какую максимальную стоимость драгоценных камней вы можете забрать.

Вход

Ввод M (M<=10) в первой строке указывает на наличие M наборов данных. Введите N и C в первой строке каждого набора данных, указав количество драгоценных камней и рюкзака.
Количество; следующая строка вводит N групп (si, vi), si и vi — целые числа, обозначающие размер и стоимость каждого драгоценного камня.

Выход

Выведите M строк натуральных чисел, i-я строка представляет собой максимальную стоимость драгоценных камней, которую можно забрать i-й группой данных, при этом рюкзак не обязательно должен быть полным.

Образец ввода

3
3 10
1 3 2 5 7 2
3 10
1 3 2 5 6 2
5 10
5 6 5 7 2 8 8 1 5 9

Пример вывода

10
10
17

2. Анализ проблемы

Нет сомнений в том, что задача должна решаться с помощью динамического программирования.

Определите массив dp, где dp[i][j] представляет собой максимальное значение, которое можно получить, положив первые i предметов в рюкзак вместимостью j. Для i-го предмета можно рассмотреть положить его в рюкзак или нет, поэтому можно получить уравнение перехода состояния:

dp[i][j] = max(dp[i-1][j], dp[i-1][j-si]+vi)

Где si и vi представляют размер и стоимость i-го элемента соответственно. Если в рюкзак положить i-й предмет, то вместимость, которую он занимает, равна j-si, а максимальное значение, которое можно получить в это время, равно dp[i-1][j-si]+vi, то есть первый i- 1 Максимальное значение, которое можно получить, положив предмет в рюкзак вместимостью j-si плюс стоимость i-го предмета. Если i-й предмет не положить в рюкзак, максимальное значение, которое можно получить в это время, равно dp[i-1][j], то есть значение, которое можно получить, положив первый i-1 предметов в рюкзак вместимостью j максимального значения.

Окончательный ответ — dp[N][C], это максимальное значение, которое можно получить, положив N предметов в рюкзак вместимостью C.

3. Пример кода

using namespace std;

const int MAXN = 505;
const int MAXC = 105;

int s[MAXN], v[MAXN];
int dp[MAXC];

int main() {
    int M;
    cin >> M;
    while (M--) {
        int N, C;
        cin >> N >> C;
        for (int i = 1; i <= N; i++) {
            cin >> s[i] >> v[i];
        }

        for (int i = 0; i < C + 1; i++) {
            dp[i] = 0;
       }
        for (int i = 1; i <= N; i++) {
            for (int j = C; j >= s[i]; j--) {
                dp[j] = max(dp[j], dp[j - s[i]] + v[i]);
            }
        }

        cout << dp[C] << endl;
    }
    return 0;
}

解释:for (int i = 1; i <= N; i++) {             for (int j = C; j >= s[i]; j--) {                 dp[j] = max(dp[j], dp [j - s[i]] + v[i]);             }         }



Приведенный выше код является основной частью задачи о рюкзаке 0/1, использующей идею динамического программирования. В частности, мы используем двумерный массив dp[i][j] для представления максимального значения, которое первые i драгоценных камней могут получить при ограничении вместимости рюкзака j. Поскольку нам нужна информация только из предыдущей строки, двумерный массив можно оптимизировать до одномерного массива dp[j].

Далее мы рассматриваем каждый драгоценный камень по очереди, и для каждого драгоценного камня нам нужно рассмотреть оба случая как ставить, так и не класть. Если мы не кладем текущий камень, то максимальное значение, которое можно получить при ограничении вместимости рюкзака j, равно dp[j]; если мы кладем текущий камень, то максимальное значение, которое можно получить при ограничении вместимости рюкзака j равно Значение dp[js[i]]+v[i], где s[i] представляет размер текущего драгоценного камня, а v[i] представляет стоимость текущего драгоценного камня. Поскольку мы можем вставить текущий драгоценный камень только один раз, поэтому при обновлении массива dp нам нужно использовать функцию max, чтобы выбрать максимальное значение, которое можно получить, вставив или не вставив текущий драгоценный камень.

Поскольку нам нужно пройти j сзади наперед, окончательный ответ будет dp[C].

Guess you like

Origin blog.csdn.net/lyhizjj/article/details/130624032