Dynamic programming (knapsack problem)

Posted by cupboy on Wed, 09 Feb 2022 16:34:44 +0100

A - upper step 2

Xiaogua wants to go up a total of N steps. Due to the special leg length of xiaogua, he can only go up 1 or 3 or 5 steps at a time. Xiaogua wants to know how many ways he can get up these n steps. Can you help him?

Input
An integer n (n < = 100000) in a row indicates that there are n steps in total.
Output
An integer in a row represents the result of the remainder of 100003 for the number of schemes on the steps of the melon.
Sample
Inputcopy Outputcopy
3 2

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int n;
	cin>>n;
	vector<long long>dp(n+1);
	dp[0]=1;
	dp[1]=1;
	dp[3]=1;
	dp[5]=1;
	for(int i=2;i<=n;i++)
	{
		if(i>=3&&i>=5)
		{
			dp[i]=dp[i-1]+dp[i-3]+dp[i-5];
		}
		else
		{
			if(i>=3)
			{
				dp[i]=dp[i-1]+dp[i-3];
			}
			else
				dp[i]=dp[i-1];
		}
		dp[i]%=100003;
	}
	cout<<dp[n];
	return 0;
 } 

B - numeric triangle

7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

(Figure 1)

Figure 1 shows a numeric triangle. There are many different paths from the top to the bottom of the triangle. For each path, add up the number above the path to get a sum. Your task is to find the maximum sum.

Note: each step on the path can only go from one number to the nearest number on the left or right of the next layer.
Input
The input line is an integer n (1 < n < = 100), which gives the number of lines of the triangle. The following N lines give the number triangle. The range of numbers on the number triangle is between 0 and 100.
Output
Output the maximum sum.
Sample
Inputcopy
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Outputcopy
30

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int n;
	cin>>n;
	vector<vector<int> >dp(n+1,vector<int>(n+1));
	vector<vector<int> >a(n+1,vector<int>(n+1));
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=0;i<=n;i++)
	{
		dp[i][0]=0;
		dp[0][i]=0;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=i;j++)
		{
			dp[i][j]=max(dp[i-1][j],dp[i-1][j-1])+a[i][j];
			ans=max(ans,dp[i][j]);
		}
	}
	cout<<ans;
	return 0;
 } 

C - matrix access problem

There are different positive integers in an N*N matrix. After passing through this lattice, you can get the reward of corresponding value. Go from top left to bottom right, and only go down and right to find the maximum value you can get.

For example: 3 * 3 square.

1 3 3

2 1 3

2 2 1

The maximum value that can be obtained is: 11.

Input
Line 1: n, where n is the size of the matrix. (2 < = n < = 500) line 2 - N + 1: n numbers in each line, separated by spaces, corresponding to the value of rewards in the grid. (1 <= N[i] <= 10000)
Output
Output the maximum value that can be obtained.
Sample
Inputcopy
3
1 3 3
2 1 3
2 2 1
Outputcopy
11

#include<iostream>
#include<vector>
using namespace std;
int main()
{
	int n;
	cin>>n;
	vector<vector<int> >dp(n+1,vector<int>(n+1));
	vector<vector<int> >a(n+1,vector<int>(n+1));
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			cin>>a[i][j];
		}
	}
	for(int i=0;i<=n;i++)
	{
		dp[i][0]=0;
		dp[0][i]=0;
	}
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			dp[i][j]=max(dp[i-1][j],dp[i][j-1])+a[i][j];
			ans=max(ans,dp[i][j]);
		}
	}
	cout<<ans;
	return 0;
 } 

D - Knapsack Problem

Take out several items from N items and put them in a backpack with a capacity of W. the volume of each item is W1, W2... Wn (Wi is an integer), and the corresponding value is P1,P2... Pn (Pi is an integer). Seek the maximum value that the backpack can hold.

Where 1 < = n < = 100, 1 < = w < = 10000, each item 1 < = wi, PI < = 10000.

Input
On the first line, enter two integers N and W; Line 2 ~ N+1, two integers Wi and Pi in each line, representing the volume and value of each article respectively.
Output
The maximum value that the output can accommodate.
Sample
Inputcopy
3 6
2 5
3 8
4 9
Outputcopy
14

#include<iostream>
#include<vector>
using namespace std;
int weight[110];
int value[110];
int dp[110][10010];
int main()
{
	int n,W;
	cin>>n>>W;
	for(int i=1;i<=n;i++)
	{
		cin>>weight[i]>>value[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=W;j++)
		{
			dp[i][j]=dp[i-1][j];
			if(j>=weight[i])
			{
				dp[i][j]=max(dp[i-1][j-weight[i]]+value[i],dp[i-1][j]);
			}
		}
	}
	cout<<dp[n][W];
	return 0;
 } 

E - full backpack

There are N items and a backpack with a capacity of V. there are unlimited items available for each item. The volume of article I is v[i], and the value is c[i].

Now please select some items to load 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.

Where 1 < = n < = 100, 1 < = V < = 50000, 1 < = v [i], C [i] < = 10000.

Input
Input two numbers N and V in the first line, which respectively represent the number of items and the volume of the backpack; The number of [i] and [v] of each kind of article in the second row, respectively;
Output
Output a number that represents the maximum value
Sample
Inputcopy
2 11
2 3
6 14
Outputcopy
20

#include<iostream>
#include<vector>
using namespace std;
int weight[110];
int value[110];
int dp[50050];
int main()
{
	int n,W;
	cin>>n>>W;
	for(int i=1;i<=n;i++)
	{
		cin>>weight[i]>>value[i];
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=weight[i];j<=W;j++)
		{
			dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
		}
	}
	cout<<dp[W];
	return 0;
 }

F - Knapsack Problem V2

There are N items, and the number of each item is C1, C2... Cn. Select several pieces from them and put them in the backpack with the capacity of W. the volume of each item is W1, W2... Wn (Wi is an integer), and the corresponding value is P1,P2... Pn (Pi is an integer). Seek the maximum value that the backpack can hold.

Where 1 < = n < = 100, 1 < = w < = 50000, 1 < = wi, PI < = 10000, 1 < = CI < = 200.

Input
Line 1, 2 integers, separated by spaces between N and W. N is the type of goods and W is the capacity of the backpack. Line 2 ~ N+1, with 3 integers in each line. Wi, Pi and Ci are the volume, value and quantity of the article respectively.
Output
The maximum value that the output can accommodate.
Sample
Inputcopy
3 6
2 2 5
3 3 8
1 4 1
Outputcopy
9

#include<iostream>
#include<vector>
using namespace std;
vector<int>w;
vector<int>v;
vector<int>c;
int dp[50050];
int main()
{
	int n,W;
	cin>>n>>W;
	w.push_back(0);
	v.push_back(0);
	c.push_back(0);
	for(int i=1;i<=n;i++)
	{
		int wi,vi,ci;
		cin>>wi>>vi>>ci;
		w.push_back(wi);
		v.push_back(vi);
		c.push_back(ci);
	}
	for(int i=1;i<=n;i++)
	{
		if(c[i]>1)
		{
			for(int j=1;j<=c[i]-1;j++)
			{
				w.push_back(w[i]);
				v.push_back(v[i]);
			} 	
		}
	}
	for(int i=1;i<w.size();i++)
	{
		for(int j=W;j>=w[i];j--)
		{
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
		}
	}
	cout<<dp[W];
	return 0;
 } 

G - longest ascending subsequence

The sequence bi of a number, when B1 < B2 <... < BS, we call this sequence ascending. For a given sequence (a1, a2,..., aN), we can get some ascending subsequences (ai1, ai2,..., aiK), where 1 < = I1 < I2 <... < IK < = n. For example, for the sequence (1, 7, 3, 5, 9, 4, 8), there are some ascending subsequences, such as (1, 7), (3, 4, 8) and so on. The longest length of these subsequences is 4, such as subsequences (1, 3, 5, 8)

Your task is to find the length of the longest ascending subsequence for a given sequence.
Input
The first line entered is the length N of the sequence (1 < = N < = 1000). The second line gives N integers in the sequence, all of which have values ranging from 0 to 10000.
Output
The length of the longest ascending subsequence.
Sample
Inputcopy
7
1 7 3 5 9 4 8
Outputcopy
4

#include<iostream>
#include<vector>
using namespace std;
vector<int>w;
vector<int>v;
vector<int>c;
int dp[50050];
int main()
{
	int n,W;
	cin>>n>>W;
	w.push_back(0);
	v.push_back(0);
	c.push_back(0);
	for(int i=1;i<=n;i++)
	{
		int wi,vi,ci;
		cin>>wi>>vi>>ci;
		w.push_back(wi);
		v.push_back(vi);
		c.push_back(ci);
	}
	for(int i=1;i<=n;i++)
	{
		if(c[i]>1)
		{
			for(int j=1;j<=c[i]-1;j++)
			{
				w.push_back(w[i]);
				v.push_back(v[i]);
			} 	
		}
	}
	for(int i=1;i<w.size();i++)
	{
		for(int j=W;j>=w[i];j--)
		{
			dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
		}
	}
	cout<<dp[W];
	return 0;
 } 

H - longest common subsequence

For two given sequences, the longest common subsequence length is requested.

The subsequence of a sequence is defined as a sequence that can be obtained by deleting some elements and keeping the relative order of the remaining elements unchanged.

Input format
In the first line, two integers n,mn,m represent the length of the two sequences.

The second line contains nn integers a_1,a_2, \ldots ,a_na
1

,a
2

,...,a
n

, representing the first sequence.

Second line mm integer b_1,b_2, \ldots ,b_mb
1

,b
2

,...,b
m

, representing the second sequence.

Output format
Output the longest common subsequence length of two sequences.

Sample
Inputcopy Outputcopy
4 5
1 2 4 5
4 1 3 3 2
2
Data range and tips
There are two subtasks in this topic.

For all data, 1 \leq n,m,a_i,b_i \leq 700001≤n,m,a
i

,b
i

≤70000.

Subtask 1 (50 points): n,m \leq 5000n,m ≤ 5000.

Subtask 2 (50 points): no special restrictions.

The data is random and may be weak. Welcome hack.

#include<iostream>
#include<vector>
using namespace std;
vector<int>w;
vector<int>v;
int main()
{
	int n,m;
	cin>>n>>m;
	w.push_back(0);
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		w.push_back(x);
	}
	v.push_back(0);
	for(int i=1;i<=m;i++)
	{
		int x;
		cin>>x;
		v.push_back(x);
	}
	vector<vector<int> >dp(n+1,vector<int>(m+1));
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(w[i]==v[j])
			{
				dp[i][j]=dp[i-1][j-1]+1;
			}
			else
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
		}
		//cout<<dp[i]<<" ";
	}
	cout<<dp[n][m];
	return 0;
 } 

J - Maximum sub segment sum of circular array

For the cyclic sequence a[1],a[2],a[3],..., a[n] composed of N integers, find the maximum value of the sum of continuous sub segments of the sequence such as a[i]+a[i+1] +... + a[j] (cyclic sequence refers to the sequence in which n numbers form a circle, so it is necessary to consider a[n-1],a[n],a[1],a[2]). When all the given integers are negative, the sum is 0.
For example: - 2,11, - 4,13, - 5, - 2, and the largest sub segment is: 11, - 4,13. And are 20.
Input
Line 1: length n of integer sequence (2 < = n < = 50000) line 2 - N+1: n integers (- 10 ^ 9 < = s [i] < = 10 ^ 9)
Output
Outputs the maximum sub segment sum of the circular array.
Sample
Inputcopy
6
-2
11
-4
13
-5
-2
Outputcopy
20

#include<iostream>
#include<vector>
#include<limits.h>
using namespace std;
int n;
typedef long long ll;
ll fun(vector<int>&nums,vector<ll>&dp)
{
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		if(dp[i-1]>=0)
			dp[i]=dp[i-1]+nums[i];
		else
			dp[i]=nums[i];
		ans=max(ans,dp[i]);
		//cout<<dp[i]<<" ";
	}
	return ans;
}
int main()
{
	cin>>n;
	vector<int>nums(n+1);
	vector<ll>dp(n+1);
	for(int i=1;i<=n;i++)
	{
		cin>>nums[i];
	}
	ll sum=0;//Record sum 
	ll ans=0;
	ll p=0,q=0;
	ll maxa=0;//Record the maximum sub segment and 
	ll maxb=0;//Record the minimum sub segment and 
	for(int i=1;i<=n;i++)
	{
		sum+=nums[i];
		p+=nums[i];
		q+=nums[i];
		if(p<0)
			p=0;
		maxa=max(maxa,p);
		if(q>0)
			q=0;
		maxb=min(maxb,q);
	}
//	cout<<sum<<endl;
//	cout<<maxa<<" "<<maxb<<endl; 
	ans=max(maxa,sum-maxb);
	cout<<ans;
	return 0;
 } 

I - stone merge

II There are N piles of stones. The weight of each pile is a[i], which are arranged in a straight line. Only two adjacent piles can be combined at a time until they are combined into one pile. Ask what is the final minimum cost.

#include<iostream>
#include<vector>
#include<limits.h>
using namespace std;
typedef long long ll;
int INF=99999999;
int main()
{
	int n;
	cin>>n;
	vector<int>w(n+1);//gravel 
	vector<int>sum(n+1);
	for(int i=1;i<=n;i++)
	{
		cin>>w[i];
		sum[i]=sum[i-1]+w[i];
	}
	vector<vector<int> >dp(n+1,vector<int>(n+1));
	for(int i=1;i<=n;i++)//initialization 
	{
		for(int j=1;j<=n;j++)
		{
			dp[i][j]=INF;
		}
	}
	for(int i=1;i<=n;i++)
		dp[i][i]=0;
	/*dp[i][j]Represents the minimum cost of merging stone i to stone j*/	
	for(int len=2;len<=n;len++)//length 
	{
		for(int i=1;i<=n-len+1;i++)
		{
			int j=i+len-1;
			for(int k=i;k<j;k++)
			{
				//The sum of the minimum cost divided into i to k,k+1 to j plus the cost of i to j itself
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]); 
			}
		}
	}
	cout<<dp[1][n];
	return 0;
 } 

Topics: C++ Algorithm Dynamic Programming