Dynamic Programming - Knapsack Problem

Dynamic Programming

knapsack problem

01 backpack problem

dynamic programming

  • status indicationf[i][j]
    • Collection: All selection methods that consider the first i items and whose volume is not greater than j
    • Attribute: Max
  • State Computing: Partitioning of Collections

There are N items and a backpack with capacity V. Each item can only be used once.

The volume of the i-th item is vi v_ivi,This is wi w_iwi

Solve which items to put into the backpack so that the total volume of these items does not exceed the capacity of the backpack and the total value is the largest.
output the maximum value.

input format

In the first line, two integers, N and V, are separated by spaces, representing the number of items and the volume of the backpack respectively.

Next there are N lines, each with two integers vi , wi v_i,w_ivi,wi, separated by spaces, respectively represent the volume and value of the i-th item.

output format

Output an integer representing the maximum value.

data range

0<N,V≤10000<N,V≤1000
0<vi,wi≤10000< v i , w i v_i,w_i vi,wi≤1000

input sample
4 5
1 2
2 4
3 4
4 5
Sample output:
8
two dimensional
  • Definition of state f[i][j]: the first i items, the optimal solution (maximum value) under knapsack capacity j

  • When the capacity of the knapsack is sufficient, it is necessary to decide whether to choose the i-th item or not:

    • do not choosef[i][j] = f[i-1][j]
    • selectf[i][j]=f[i-1][j-v[i]]+w[i]
    • Our decision is how to get the maximum value, so the above two cases takemax()

    the code

    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 1010;
    int v[N], w[N];
    int f[N][N];
    int main() {
          
          
        int n, m;
        cin >> n >> m;
        for (int i = 1; i <= n; ++i)
            cin >> v[i] >> w[i];
        for (int i = 1; i <= n; ++i) {
          
          
            for (int j = 1; j <= m; ++j) {
          
          
                f[i][j] = f[i - 1][j];
                if (v[i] <= j)  f[i][j] = max(f[i][j], f[i -1][j - v[i]] + w[i]);
            }
        }
        cout << f[n][m];
        return 0;
    }
    
One-dimensional

The state we defined f[i][j]can obtain any legal optimal solution of i and j, but the title only requires the final state f[n][m], so we only need a one-dimensional space to update the state.

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1010;
int v[N], w[N];
int f[N];
int main() {
    
    
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> v[i] >> w[i];
    for (int i = 1; i <= n; ++i) {
    
    
        for (int j = m; j >= v[i]; --j) {
    
    
            
            
            f[j] = max(f[j], f[j - v[i]] + w[i]);
        }
    }
    cout << f[m];
    return 0;
}

complete knapsack problem

dynamic programming

  • status indicationf[i][j]
    • Collection: All selection methods that consider the first i items and whose volume is not greater than j
    • Attribute: Max
  • State Computing: Partitioning of Collections

f[i][j]Select k items for the i-th item, first remove k items i, and then return k items i

f[i][j] = f[i-1][j-v[i]*k]+w[i]*k

violent dp

#include <iostream>

using namespace std;
const int N = 1010;
int f[N][N],v[N], w[N];
int main() {
    
    
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) 
        cin >> v[i] >> w[i];
    for (int i = 1; i <= n; ++i) {
    
    
        for (int j = 1; j <= m; ++j) {
    
    
            for (int k = 0; k * v[i] <= j; ++k) {
    
    
                f[i][j] = max(f[i][j],f[i - 1][j - k * v[i]] + k * w[i]);
                // cout << f[i][j];
            }
        }
    }
    cout << f[n][m];
    return 0;
}

we can find out

f[i,j]=Max(f[i-1,j],f[i-1,j-v]+w,f[i-1.j-2v]+2w,...,f[i-1.j-kv]+kw

f[i,j-v]=Max( f[i-1,j-v],f[i-1.j-2v]+w,...,f[i-1.j-kv]+(k-1)w

the code

#include <iostream>
// #include <algorithm>
using namespace std;
const int N = 1010;
int f[N][N],v[N], w[N];
int main() {
    
    
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) 
        cin >> v[i] >> w[i];
    for (int i = 1; i <= n; ++i) {
    
    
        for (int j = 1; j <= m; ++j) {
    
    
            f[i][j] = f[i-1][j];
            if (j >= v[i])  f[i][j] = max(f[i][j], f[i][j-v[i]] + w[i]);           
        }
    }
    cout << f[n][m];
    return 0;
}

1D code

#include <iostream>
// #include <algorithm>
using namespace std;
const int N = 1010;
int f[N],v[N], w[N];
int main() {
    
    
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) 
        cin >> v[i] >> w[i];
    for (int i = 1; i <= n; ++i) {
    
    
        for (int j = v[i]; j <= m; ++j) {
    
    
            // f[i][j] = f[i-1][j];
            f[j] = max(f[j], f[j-v[i]] + w[i]);           
        }
    }
    cout << f[m];
    return 0;
}

multiple knapsack problem

dynamic programming

  • status indicationf[i][j]
    • Collection: All selection methods that consider the first i items and whose volume is not greater than j
    • Attribute: Max
  • State Computing: Partitioning of Collections

topic description

There are N items and a backpack with capacity V.

The i item has at most si s_isipieces, the volume of each piece is vi v_ivi,This is wi w_iwi

Solve which items to put into the backpack, so that the sum of the volume of the items does not exceed the capacity of the backpack, and the sum of the values ​​is the largest.
output the maximum value.

input format

In the first line, two integers, N and V, are separated by spaces, which represent the number of items and the volume of the backpack respectively.

Next there are N lines, each with three integers vi v_ivi, w i w_i wi, s i s_i si, separated by spaces, respectively represent the volume, value and quantity of the i-th item.

output format

Output an integer representing the maximum value.

data range

0<N,V≤100
0< v i v_i vi, w i w_i wi, s i s_i si ≤100

input sample
4 5
1 2 3
2 4 1
3 4 3
4 5 2
Sample output:
10

the code

#include <iostream>
using namespace std;
const int N = 110;
int f[N][N], w[N], v[N], s[N];
int main() {
    
    
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) 
        cin >> v[i] >> w[i] >> s[i];
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
    
    
            for (int k = 0; k * v[i] <= j && k <= s[i]; ++k) {
    
    
                f[i][j] = max(f[i][j], f[i - 1][j - k * v[i]] + k * w[i]);
            }
        }
    cout << f[n][m];
    return 0;
}

When the data range expands

data range

0<N≤1000

0<V≤2000

0< vi v_ivi, w i w_i wi, s i s_i si ≤2000

f(i, j) = Max(f(i-1,j),f(i-1,j-v)+w,f(i-1,j-2v)+2w+...+f(i-1,j-sv)+sw)
f(i, j-v) = Max(f(i-1,j-v),f(i-1,j-2v)+w,f(i-1,j-3v)+2w+...+f(i-1,j-sv)+(s-1)w,f(i, j) = Max(f(i-1,j),f(i-1,j-v)+w,f(i-1,j-2v)+2w+...+f(i-1,j-(s+1)v)+sw)

So it cannot be solved by the complete knapsack problem

We can adopt the method of binary optimization +01 knapsack problem

binary optimization

Given a bunch of apples and 10 boxes, select n apples. Divide this bunch of apples into 10 boxes according to 1, 2, 4, 8, 16, ... 512, then because any number x∈[0,1023] (the 11th box can get 1024, the comment area There is a discussion on this) can be expressed from the number of apples in these 10 boxes, but the number of selections in this way is ≤10 times

the code

#include <iostream>
using namespace std;
const int N = 1e5 + 10;
int v[N], w[N];
int f[2020];
int main() {
    
    
    int n, m;
    cin >> n >> m;
    int cnt = 0;
    while (n--) {
    
    
        int a, b, s;
        cin >> a >> b >> s;
        int k = 1;
        while (k <= s) {
    
    
            v[++cnt] = a * k;
            w[cnt] = b * k;
            s -= k;
            k *= 2;
        }
        if (s){
    
    
            v[++cnt] = a * s;
            w[cnt] = b * s;
        }
    }
    n = cnt;
    for (int i = 1; i <=n; ++i) {
    
    
        for (int j = m; j >= v[i]; --j) {
    
    
            f[j] = max(f[j], f[j - v[i]] + w[i]);
        }
    }
    cout << f[m];
    return 0;
}

group knapsack problem

There are N sets of items and a backpack with capacity V.

There are several items in each group, and only one item in the same group can be selected at most.
The volume of each item is vi , j v_{i,j}vi,j, the value is wi , j w_{i,j}wi,j, where i is the group number and j is the group number.

Solve which items to put into the backpack so that the total volume of the items does not exceed the capacity of the backpack and the total value is the largest.

output the maximum value.

input format

The first line has two integers N, V, separated by a space, which represent the number of item groups and the capacity of the backpack respectively.

Next there are N sets of data:

  • The first row of each set of data has an integer S i S_{i}Si, indicating the number of items in the i-th item group;
  • Each set of data is followed by S i S_{i}SiLines, each line has two integers vi , j v_{i,j}vi,j, w i , j w_{i,j} wi,j, separated by spaces, represent the volume and value of the j-th item in the i-th item group respectively;
output format

Output an integer representing the maximum value.

data range

0<N,V≤100
0<Si≤100
0< v i , j v_{i,j} vi,j, w i , j w_{i,j} wi,jj≤100

input sample
3 5
2
1 2
2 4
1
3 4
1
4 5
Sample output:

8

the code

#include <iostream>
using namespace std;
const int N = 110;
int v[N], w[N];
int f[110];
int main() {
    
    
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
    
    
        int s;
        cin >> s;
        for (int j = 1; j <= s; ++j) {
    
    
            cin >> v[j] >> w[j];
        }
        for (int k = m; k >= 1; --k) {
    
    
            for (int j = 1; j <= s; ++j) {
    
    
                if (v[j] <= k)
                    f[k] = max(f[k], f[k - v[j]] + w[j]);
            }
        } 
    }
    cout << f[m];
    return 0;
}

Guess you like

Origin blog.csdn.net/weixin_64632836/article/details/128991820