Treatment of knapsack problem

Some development and treatment of knapsack problem

Packing problem

Title Description:

There is a box with a capacity of V and n items at the same time. Each item has a volume (positive integer). It is required to take any number of n items into the box to minimize the remaining space of the box.

Core idea

\(f[i] \) record the maximum capacity when the volume is m

Transfer equation: \ (f_j=max(f_j,f_{j-u}+u) \)

Particularity: the value and capacity here are the same thing

Collection of pet elves

Title Description

There is a backpack. The first capacity is M and the second capacity is V. there are N items in total. Ask how many can be loaded at most. At this time, how much can the second capacity be left at most

\(0<N≤1000\)
\(0<M≤500\)
\(0<V≤100\)

Core idea:

This problem was originally a simple two-dimensional cost knapsack problem, but there are two points worth studying:

1. How can I find the maximum number and the maximum number left

We set \ (f_{i,j} \) to represent the largest collected sprites when \ (m \) is \ (I \) and \ (v \) is \ (j \).

Then we can list the DP of an ordinary triple cycle

But it's not over yet. We can install at most. How much can we expect

This is also easy to do. If the \ (f_{i,j} \) array is larger than the \ (ans \) array, then \ (tag \) is directly marked as \ (j \)

But if they are equal, take the smaller one

Finally, output directly

int f[N][N],u[N],v[N];
int n,m,q,tagans,tag;
int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=q;i++) scanf("%d%d",&u[i],&v[i]);
    for(int i=1;i<=q;i++)
        for(int j=n;j>=u[i];j--)
            for(int k=m;k>=v[i];k--)
                f[j][k]=max(f[j][k],f[j-u[i]][k-v[i]]+1);
    for(int j=0;j<=n;j++){
        for(int k=0;k<m;k++){
            if(f[j][k]>tagans) tagans=f[j][k],tag=k;
            else if(f[j][k]==tagans && tag>k) tag=k;
    printf("%d %d",tagans,m-tag);
    return 0;
}
2. What do we find by observing the data

The time complexity of the first method is \ (O(nmV) \)

Firstly, we can understand that for a backpack, \ (f_{i,j} \) represents the maximum value when the volume of the \ (I \) item is \ (j \)

At this time, the \ (v[i] \) and \ (w[i] \) are interchangeable, but the meaning of the \ (f \) array will be changed

Let's come back to this question. Since \ (V \) is very small, we consider using \ (V \) many times

Therefore, our new \ (f \) array represents v as \ (i \), and the smallest \ (m \) is used to enumerate the \ (j \) article

So we can write it another way at this time

const int inf=0x3f3f3f3f;
int f[N][N];
int n,m,q;
int main(){
    memset(f,0x3f,sizeof(f));
    scanf("%d%d%d",&n,&m,&q);
    f[0][0]=0;
    for(int i=1,u,v;i<=q;i++){
        scanf("%d%d",&u,&v);
        for(int j=m;j>=v;j--)
            for(int k=i;k;k--)
                if(f[j-v][k-1]+u<=n) f[j][k]=min(f[j][k],f[j-v][k-1]+u); 
    }
    for(int k=q;~k;k--)
        for(int j=0;j<m;j++)
            if(f[j][k]!=inf) return printf("%d %d\n",k,m-j),0; 
    return 0;
}

At this time, the analysis complexity is \ (O(V^2m) \) which is about 5e6. The previous one is 5e7, which is still very different

Take a look at the time difference between the two. Indeed, there is still a gap

Digital combination

Title Description:

Given \ (n \) positive integers \ (A1,A2,..., An \), select several numbers from them, make their sum \ (m \), and find out how many options there are.

\(1≤n≤100\)
\(1≤m≤10000\)
\(1≤Ai≤1000\)

Core idea:

This question is the number of required schemes. It is a very classic DP

First, let \ (f_{j} \) represent the number of schemes whose sum is \ (J \)

Then for \ (J \), if there is \ (I ∈ [1,n] \) and \ (a[i]+k=j \), then our \ (f[j]=f[j]+f[k] \) means that all the scheme numbers of \ (f_k \) can be added to form \ (J \), so we can get \ (f_j+=f_j-a[i] \)

Because each number can only be selected once, we can directly operate with 01 backpack

Note: f[0] should be assigned to 1

int f[N],a[N];
int n,m;
int main(){
    read(n),read(m);
    f[0]=1;
    for(int i=1;i<=n;i++) read(a[i]);
    for(int i=1;i<=n;i++){
        for(int j=m;j>=a[i];j--){
            f[j]=f[j]+f[j-a[i]];
        }
    }
    cout<<f[m];
    return 0;
}

Monetary system

Title Description:

Give you a monetary system with n denominations, and find out how many schemes there are to form a currency with a denomination of m.

Core idea:

This question is similar to the previous one, but we found that our current increase can be spliced with several pieces of uniform price, and it's OK to directly complete the backpack

#define int long long
int f[N];
signed main(){
    int n,m;
    cin>>n>>m;
    f[0]=1;
    for(int i=1;i<=n;i++){
        int u; cin>>u;
        for(int j=u;j<=m;j++) f[j]+=f[j-u];
    }
    cout<<f[m];
    return 0;
}

Hybrid knapsack problem

Title Description

There are \ (N \) items and a backpack with a capacity of \ (V \).

There are three categories of items:

  • Class I items can only be used once (01 backpack);
  • The second kind of goods can be used unlimited times (complete backpack);
  • The third category can only be used \ (si \) times at most (multiple backpacks);

Each volume is \ (vi \) and the value is \ (wi \).

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

Core idea:

Let's consider a problem. In binary optimization, we split each item. At this time, we can directly apply the idea of binary splitting. The 01 knapsack is transformed into a multiple knapsack of \ (s=1 \), and the complete knapsack is transformed into a multiple knapsack of \ (s=m/u \)

Finally, the multiple knapsack idea is used to solve the QAQ

#include <bits/stdc++.h>
using namespace std;
int n,m,v[100010],w[100010],f[100010];
int main(){
    cin>>n>>m;
    int cnt=1;
    for(int i=1;i<=n;i++){
        int a,b,s;
        cin>>a>>b>>s;
        int k=1;
        if(s<0)s=1;
        else if(s==0)s=m/a;
//First convert 01 backpack and multiple backpacks into multiple backpacks. If it is a complete backpack, in the optimal case, only the total volume / the volume of the item can be rounded down 
        while(k<=s){
            v[cnt]=a*k;
            w[cnt]=b*k;
            s-=k;
            k*=2;
            cnt++;
        }
        if(s>0){
            v[cnt]=s*a;
            w[cnt]=s*b;
            cnt++;
        }
    }//Binary optimization of multiple knapsacks into 01 knapsack 
    for(int i=1;i<=cnt;i++){
        for(int j=m;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]); //01 knapsack problem
    cout<<f[m]<<endl;
    return 0;
}

Posted by wei on Sun, 31 Oct 2021 10:45:19 -0700