"Fool code template" solves three basic problems

Posted by Hoangsta on Tue, 08 Mar 2022 12:49:30 +0100

"Fool code template" solves three basic problems

   Preface: the focus of this article is the establishment and application of fool code template. In the part of knapsack principle, you may talk less and jump. You can focus on absorbing the knowledge of "code template part" and the application method of code template in the later half of the actual battle.

  if you are not clear about the knowledge of knapsack principle, you can collect high-quality knapsack blogs from other bloggers~

Relevant knowledge

Basic model of backpack ❔

  we have a backpack with a capacity of V and several items. Under certain restrictions (each item occupies a certain capacity), how many valuable items can we put in at most?

Classification of knapsack problem 🎒

  01 knapsack, complete knapsack, multiple knapsack, two-dimensional cost knapsack, mixed three kinds of knapsack, group knapsack and dependent knapsack.
(PS: the most common and basic types of backpack problems are the first three types of backpacks)

01 Backpack

Question method 🌌

  there are N items and a backpack with a capacity of V. The value of article I is w[i], and the volume is v[i].
  solution: what is the maximum value of the backpack?

Problem characteristics

  there is only one item of each kind, and you can choose to put it or not.

Problem solution

   suppose there are N items, the backpack capacity is V, the value of the i-th item is w[i], and the volume is v[i].
Consider only the first item:
   traversal volume V-v[1], use dp[j] to represent the maximum value that the backpack can hold when the backpack volume is j, and the dp array is initialized to 0 before use. In the first traversal, it is obvious that the maximum value is the value of the item.
Only the first two items are considered:
   traverse volume V-v[2], update dp array, but how to update dp array?
  we can divide the placement of items when the dp array is updated into two types: 1 ️⃣ dp[j] does not contain item 2 ️⃣ dp[j] contains item 2.

  • one ️⃣: The maximum value excluding the second item has been calculated just now, that is, the old dp[j], which does not need to be updated.

  • two ️⃣: The maximum value of the second item is the value of the second item w[2] ➕ The maximum value dp[j-v[2]] when the backpack capacity is less than v[2].

    To sum up, we can write the update formula of dp array at this time (only considering the first two items), that is, our "state transition equation" of dynamic programming: dp[j]=max(dp[j],w[2]+dp[j-v[2]);
      continue to consider only the first 3 and 4 items until N items are considered, and the final result is stored in dp[N].

Complete Backpack

Question method 🌌

   there are N items and a backpack with a capacity of V. each item can be taken repeatedly for unlimited times. The value of article I is w[i], and the volume is v[i].
  solution: what is the maximum value of the backpack?

Problem characteristics

  there are countless items of each kind. You can choose whether to put them or how many.

Problem solution

The traversal order of the knapsack [i-81v #] is completely the same as the traversal order of the knapsack [i-81v] - V.

What if it has to be full / minimum?

Minor modification ①: what if the backpack must be filled?
    in our previous problem environment, there was no restriction that the backpack must be filled. If we add another condition that the backpack must be filled, how should we change the program? You only need to modify the initialization of dp array according to the "relative principle".
What is the principle of relativity?
   if we require the maximum value, we will initialize all array elements of dp array to negative infinity except that dp[0] is 0.
   if we require the minimum value, we will initialize all array elements of dp array to positive infinity except that dp[0] is 0.
Minor modification ②: what if the minimum value is required?
   directly modify the max in the state transition equation to min.

01 & complete 🎒 Summary: three bases

  determine whether the volume layer traversal of the backpack is in order or reverse order according to the name difference of the backpack (01 backpack or complete backpack).
   according to the restriction difference of knapsack (not full or full), decide whether the initialization of dp array is directly 0 or according to the principle of relativity.
   according to the purpose difference of the backpack (requiring the maximum value or the minimum value), determine whether the maximum function in the state transition equation is min or max.

Core code template - 01& complete 🎒

//Choose three codes that match the meaning of the question
//Description of program variables: n-total number of items, v-knapsack volume, v-volume of each item, w-value of each item, dp[j] - Maximum knapsack value when knapsack volume is j
//Guidelines for template use:
//① : make sure you don't want to fill it up first and make the first code selection (select one that meets and delete / comment others);
//② : then make the second code selection according to whether it is a 01 backpack or a complete backpack (can you take the same item indefinitely);
//③ : finally, see whether to find the maximum value or the minimum value of the backpack, and make the third code choice.

//First code selection:
		memset(dp,0,sizeof(dp)); //Full is not required
//		dp[0]=0; // Option 1: fill it up and find the maximum value of the backpack 
//		for(int i=1;i<=V;i++)dp[i]=-1e9; 
//		dp[0]=0; // Option 2: fill it up and find the minimum value of the backpack value 
//		for(int i=1;i<=V;i++)dp[i]=1e9;

		for(int i=1;i<=n;i++)
//Second code selection:
			for(int j=V;j>=v[i];j--) //01 knapsack / multiple knapsack traversal sequence
//			For (int j = v [i]; J < = V; j + +) / / alternative: complete knapsack traversal order 

//Third code selection:
				dp[j]=max(dp[j],dp[j-v[i]]+w[i]); //Seeking maximum value
//				dp[j]=min(dp[j],dp[j-v[i]]+w[i]); // Alternative: minimum value 
		cout<<dp[V]<<endl;   

Multiple Backpack

Question method 🌌

   there may be more than one item, so it is not the familiar 01 backpack. At the same time, its number is not countless, so it is not the familiar complete backpack. It has a fixed number of items with the same number.

Problem characteristics

  each item has a fixed number of pieces. You can choose whether to put it or how many, but the maximum number is limited.

Problem solution

   some students may think that the number of repetitions can be changed to the number of repetitions. One backpack can be input repeatedly. However, the problem is that the time complexity is O (number of repetitions). If the number of repetitions is very large, it is likely to lead to TLE.
   what should we do? It's very simple. We just need to binary group the backpacks and treat them as multiple different backpacks.
  for example, we have 10 items with a volume of 2 and a value of 4. We can divide it into four groups: one in the first group, two in the second group, three in the third group and four in the fourth group. Then we equivalent each group to a new item. If you group in the above way, the equivalent result is:
     group I → 1 article with volume of 2 and value of 4;
     group II → an article with a volume of 4 and a value of 8;
     group III → an article with a volume of 6 and a value of 12;
     group 4 → an article with a volume of 8 and a value of 15.
   in this way, 10 duplicate items with volume of 2 and value of 4 become the above four new items with different values and volumes. We can use 01 knapsack to solve the familiar problem. At this time, the time complexity is O(log2 repetition number), and the time complexity is greatly reduced.
  the general idea is like this, but how to subdivide it? In other words, what are the rules of segmentation?
According to the power principle, we can use the positive power of integers to represent everything.
  the power of   2 is 1, 2, 4, 8, 16,..., 2n. Our allocation idea is to allocate binary numbers from small to large until they cannot be divided, and the rest will become a group alone.
   take the 10 duplicate items as an example, our distribution process is as follows:

Remaining before allocationDistributionNumber remaining after allocation
First allocation1019
Second distribution927
Third distribution743
Fourth distribution333

   it can be clearly seen from the above table that the first three distributions are all the distribution of a second power. The fourth distribution was supposed to distribute 8, but it is obvious that the remaining number before distribution is not enough to divide so many, so we can follow the principle that the remaining can not be divided into a group alone. If the remaining is 3, we will make the final distribution according to 3.

Core code template - multiple 🎒

   as follows (take x repeated items with value a and volume b as an example):

void classify(){ //All the following variables should be defined as global variables
		t=1,cnt=1; //t stands for the number of remaining binary allocations, and cnt stands for the number of allocations at present
		while (x>=t){
			v[cnt]=a*t,c[cnt++]=b*t;
			x-=t,t<<=1;
		}
		if(x){
			v[cnt]=a*x,c[cnt]=b*x;
		} 
}

   next, let's test the effect of this core code template. We randomly select two groups of data, and the test results are as follows (the results are satisfactory):

  the test code is as follows:

#include<bits/stdc++.h>
using namespace std;
int x,a,b,v[500],c[500],t,cnt;
void classify(){
		t=1,cnt=1; 
		while (x>=t){
			v[cnt]=a*t;
			c[cnt++]=b*t;
			x-=t;
			t<<=1;
		}
		if(x){
			v[cnt]=a*x;
			c[cnt]=b*x;
		} 
}
int main(){
	ios::sync_with_stdio(false);
	while(cin>>x>>a>>b){
		cout<<"Before classification: "<<endl<<x<<"The first value is"<<a<<" Volume"<<b<<"Items"<<endl; 
		memset(v,0,sizeof(v));
		memset(c,0,sizeof(c));
		classify();
		cout<<"After classification: " <<endl;
		for(int i=1;i<=cnt;i++)cout<<"1 The first value is"<<v[i]<<" Volume"<<c[i]<<"Items"<<endl;
	}	
	return 0;
} 

How do I apply the above allocation codes?

   for the multiple knapsack problem, generally, when inputting, "the number of items of this type, the volume of items of this type, the value of items of this type" is input, as shown below:

for(int i=1;i<=n;i++) //Suppose there are n kinds of backpacks
cin>>bag_num>>vv>>ww; //Enter the quantity, volume and value of the i-th item in sequence

   we introduce CNT to count the number of equivalent items (not n) after "equivalent distribution" (the content of multiple backpacks just mentioned). At first, we make the value of CNT 1, and finally make the number of items in 01 & complete backpack n=cnt-1, which is convenient for the subsequent application of 01 backpack template:

	int cnt=1;
	for(int i=1;i<=n;i++){ 
		cin>>item_num>>vv>>ww;
			int t=1; 
			while(item_num>=t){
				v[cnt]=vv*t,w[cnt++]=ww*t;
				item_num-=t,t<<=1;
			}
			if(item_num){
				v[cnt]=vv*item_num,w[cnt++]=ww*item_num;
			}
	}
	n=cnt-1; //Finally, change the total number of items before distribution to the total number of items after distribution to facilitate the subsequent application of 01 backpack template 

💥 Wang fried: three knapsack universal code template

   finally, we mix and match the three backpacks together to have the basic three backpacks universal code template. The following code comments are very detailed. If you still can't understand, you can see how the author uses this template to kill the backpack problem.

//--------------------------01 knapsack & complete knapsack & multiple knapsack の universal template--------------------------//

//Multiple knapsack allocation code. If it is multiple knapsack, cancel the comments of the following codes. The input format may be changed slightly according to different topics 
//Description of program variables: n - number of items before allocation, last cnt - number of items after allocation, item_num - duplicate quantity of current item vv - volume of current item ww - value of current item t - current binary allocation v[cnt] volume of cnt item w[cnt] value of cnt item  
//	int cnt=1;
//	for(int i=1;i<=n;i++){ 
//		cin>>item_num>>vv>>ww;
//			int t=1; 
//			while(item_num>=t){
//				v[cnt]=vv*t,w[cnt++]=ww*t;
//				item_num-=t,t<<=1;
//			}
//			if(item_num){
//				v[cnt]=vv*item_num,w[cnt++]=ww*item_num;
//			}
//	}
//	n=cnt-1; // Finally, change the total number of items before distribution to the total number of items after distribution to facilitate the subsequent application of 01 backpack template 

//Choose three codes that match the meaning of the question
//Description of program variables: n-total number of items, v-knapsack volume, v-volume of each item, w-value of each item, dp[j] - Maximum knapsack value when knapsack volume is j
//Guidelines for template use:
//① : make sure you don't want to fill it up first and make the first code selection (select one that meets and delete / comment others);
//② : then make the second code selection according to whether it is a 01 backpack or a complete backpack (can you take the same item indefinitely);
//③ : finally, see whether to find the maximum value or the minimum value of the backpack, and make the third code choice.

//First code selection:
		memset(dp,0,sizeof(dp)); //Full is not required
//		dp[0]=0; // Option 1: fill it up and find the maximum value of the backpack 
//		for(int i=1;i<=V;i++)dp[i]=-1e9; 
//		dp[0]=0; // Option 2: fill it up and find the minimum value of the backpack value 
//		for(int i=1;i<=V;i++)dp[i]=1e9;

		for(int i=1;i<=n;i++)
//Second code selection:
			for(int j=V;j>=v[i];j--) //01 knapsack / multiple knapsack traversal sequence
//			For (int j = v [i]; J < = V; j + +) / / alternative: complete knapsack traversal order 

//Third code selection:
				dp[j]=max(dp[j],dp[j-v[i]]+w[i]); //Seeking maximum value
//				dp[j]=min(dp[j],dp[j-v[i]]+w[i]); // Alternative: minimum value 
		cout<<dp[V]<<endl;   

Related topics

In essence, the three dimensions of knapsack combination are the basis of random selection.

  first: what kind of backpack is it? Is it a 01 backpack, a full backpack, or a multiple backpack? Choose the template of which kind of backpack.

  second: why don't you ask us to fill our backpacks? According to this requirement, whether it is full or not, the initialization method of the corresponding dp array in the template is selected.

  third: what is the maximum or minimum value? Flexibly modify the maximum value function.

  after positioning the above three dimensions accurately, we only need to select the corresponding code and make minor adjustments to solve the problem. For the following five questions, if you master the template, you can solve the whole question in 10 minutes, which shows that the code has strong universality and high efficiency.

1. Bone collector

Reference ideas

   according to the meaning of the topic, the topic can be positioned as "01 Backpack + not required to be full + seeking the maximum value of the backpack", which can be substituted into the template and modified slightly.

Refer to AC code

#include<bits/stdc++.h>
using namespace std;
int main(){
	ios::sync_with_stdio(false);
	int c,n,V,v[1005],w[1005],dp[1005];
	cin>>c;
	while(c--){
		cin>>n>>V;
		memset(v,0,sizeof(v));
		memset(w,0,sizeof(w));
		memset(dp,0,sizeof(dp));//Full is not required
		for(int i=1;i<=n;i++)cin>>w[i];		
		for(int i=1;i<=n;i++)cin>>v[i];
		for(int i=1;i<=n;i++)
			for(int j=V;j>=v[i];j--)//01 Backpack
                dp[j]=max(dp[j],dp[j-v[i]]+w[i]);//Seeking the maximum value of backpack
		cout<<dp[V]<<endl;
	}
	return 0;
}

2,Piggy-Bank

Reference ideas

   according to the meaning of the topic, the topic can be positioned as "complete Backpack + full requirement + minimum value of backpack", which can be substituted into the template.

Refer to AC code

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;//Request full
#define endl '\n'
int c,a,b,V,n,w[505],v[505],dp[1001000]; 
int main(){
	cin>>c;
	ios::sync_with_stdio(false);
	while(c--){
		cin>>a>>b;
		V=b-a;
		cin>>n;
		memset(w,0,sizeof(w));
		memset(v,0,sizeof(v));
		for(int i=1;i<=n;i++)cin>>w[i]>>v[i];
		dp[0]=0;  //Request full
		for(int i=1;i<=V;i++)dp[i]=inf; //Request full
		for(int i=1;i<=n;i++)
			for(int j=v[i];j<=V;j++)//Complete Backpack
				dp[j]=min(dp[j],dp[j-v[i]]+w[i]);//Find the minimum value of backpack 
		if(dp[V]==inf){
			cout<<"This is impossible."<<endl;	
		}
		else{
			cout<<"The minimum amount of money in the piggy-bank is "<<dp[V]<<"." <<endl;
		}
	}
	return 0;
}

3. Cherish the present and be grateful for life


Reference ideas

   according to the meaning of the topic, the topic can be positioned as "multiple backpacks + not required to be full + seeking the maximum value of the backpack", which can be substituted into the template.

Refer to AC code

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
#define endl '\n'
int c,a,b,V,n,w[505],v[505],dp[1001000],item_num,vv,ww; 
int main(){
	cin>>c;
	ios::sync_with_stdio(false);
	while(c--){
		cin>>V>>n;
		memset(w,0,sizeof(w));
		memset(v,0,sizeof(v));
//--------------------------------------Multiple Backpack--------------------------------------
        int cnt=1;
		for(int i=1;i<=n;i++){ 
			cin>>vv>>ww>>item_num;
				int t=1; 
				while(item_num>=t){
					v[cnt]=vv*t,w[cnt++]=ww*t;
					item_num-=t,t<<=1;
				}
				if(item_num){
					v[cnt]=vv*item_num,w[cnt++]=ww*item_num;
				}
		}
		n=cnt-1; 
//--------------------------------------Multiple Backpack--------------------------------------
		memset(dp,0,sizeof(dp)); //Full is not required
		for(int i=1;i<=n;i++)
			for(int j=V;j>=v[i];j--) //Multiple backpacks are transformed into 01 backpacks, so they are in reverse order
				dp[j]=max(dp[j],dp[j-v[i]]+w[i]); //Seeking the maximum value of backpack
		cout<<dp[V]<<endl; 
	}
	return 0;
} 

4. Ice throne


Reference ideas

   according to the meaning of the topic, the topic can be positioned as "complete Backpack + not required to be full + seeking the maximum value of the backpack", which can be substituted into the template.
   PS: the value of this question is compared with the price, and the volume is also compared with the price. Therefore, the price is both the volume and the price. We need to pay attention to this and change it flexibly.

Refer to AC code

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
#define endl '\n'
int c,a,b,V,n,w[505],v[505],dp[1001000],item_num,vv,ww; 
int main(){
	cin>>c;
	ios::sync_with_stdio(false);
	while(c--){
		cin>>V;
		memset(w,0,sizeof(w));
		memset(v,0,sizeof(v));
		v[1]=150,w[1]=150;
		v[2]=200,w[2]=200;
		v[3]=350,w[3]=350;
		memset(dp,0,sizeof(dp)); //Full is not required
		for(int i=1;i<=3;i++)
			for(int j=v[i];j<=V;j++) //Complete Backpack
				dp[j]=max(dp[j],dp[j-v[i]]+w[i]); //Seeking the maximum value of backpack
		cout<<V-dp[V]<<endl; 
	}
	return 0;
} 

5. Weight loss record


Reference ideas

   according to the meaning of the topic, the topic can be positioned as "complete Backpack + not required to be full + seeking the maximum value of the backpack", which can be substituted into the template.

Reference code

#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
#define endl '\n'
int c,a,b,V,n,w[505],v[505],dp[1001000],item_num,vv,ww; 
int main(){
	ios::sync_with_stdio(false);
	while(cin>>n){
		memset(w,0,sizeof(w));
		memset(v,0,sizeof(v));
		for(int i=1;i<=n;i++){
			cin>>w[i]>>v[i];
		}
		cin>>V;
		memset(dp,0,sizeof(dp)); //Full is not required
		for(int i=1;i<=n;i++)
			for(int j=v[i];j<=V;j++) //Complete Backpack
				dp[j]=max(dp[j],dp[j-v[i]]+w[i]); //Seeking the maximum value of backpack
		cout<<dp[V]<<endl; 
	}
	return 0;
} 

an account of happenings after the event being told

  if you have any questions during reading, you can leave a message in the comment area~
                     8195!!! Thank you~

Topics: C++ Algorithm Dynamic Programming