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; }