Dynamic programming idea

Keywords: Algorithm Dynamic Programming

0

Idea of dynamic programming: when analyzing the choice of the first i objects, under the condition that all possible values of constraints are taken, first find the optimal solution of each sub problem of constraint value, so that when analyzing the addition of the i+1 object, you can directly call the solution of one or more sub problems that have been analyzed before, Other solutions of these subproblems may not be local optimal solutions, but considering the i+1 object, they may be one of the components of the final optimal solution.
Most of dynamic planning also uses the idea of exhaustive, but:

  • The first is that it will only enumerate the optimal solution of each subproblem.
  • The second is to find a new optimal solution through state refresh, because the solution of the previous subproblem has been stored. When the new subproblem comes, it only needs to make O(n) times max comparison and store the new solution.

Dynamic programming problem solving steps

Problem abstraction, modeling, finding constraints, judging whether it meets the optimality principle, finding the recursive relationship between large and small problems, filling in tables and finding solutions.

knapsack problem

Before solving the problem, for the convenience of description, first define some variables: Vi represents the value of the ith item, Wi represents the volume of the ith item, define V(i,j): the current knapsack capacity j, the value corresponding to the best combination of the first i items, and abstract the knapsack problem (X1, X2,..., Xn, where Xi takes 0 or 1, indicating whether the ith item is selected or not).

  1. Establish the model, that is, find max(V1X1+V2X2 +... + VnXn);

  2. Find constraints, W1X1+W2X2 +... + wnxn < capacity;

  3. There are two possibilities to find a recurrence relation in the face of current commodities:

  • The capacity of the package is smaller than that of the commodity and cannot be loaded. At this time, the value is the same as that of the first I-1, that is, V(i,j)=V(i-1,j);
  • There is still enough capacity to load the commodity, but it may not reach the current optimal value, so choose the optimal one between loading and non loading, that is, V(i,j)=max {V(i-1,j), V(i-1,j-w(i))+v(i)}.

Where V(i-1,j) means no, V(i-1,j-w(i))+v(i) means the ith commodity is loaded, the backpack capacity decreases w(i), but the value increases v(i);

Thus, the recurrence relation can be obtained:

  • j<w(i) V(i,j)=V(i-1,j)
  • j>=w(i) V(i,j)=max{V(i-1,j),V(i-1,j-w(i))+v(i)}

Backtracking of optimal solution of knapsack problem:

The optimal solution of the knapsack problem can be obtained by the above method, but we don't know what goods the optimal solution consists of, so we should find out the composition of the solution by backtracking according to the optimal solution. According to the principle of filling in the form, there can be the following solution finding methods:

When V(i,j)=V(i-1,j), it means that the ith commodity is not selected, then it returns to V(i-1,j);
When V(i,j)=V(i-1,j-w(i))+v(i), it means that the ith commodity is loaded, which is part of the optimal solution. Then we have to go back to V(i-1,j-w(i));
Until i = 0, the group of all solutions will be found.

Example:

The optimal solution is V(4,8)=10, and V (4,8)= V (3,8) has V(4,8)=V(3,8-w(4))+v(4)=V(3,3)+6=4+6=10, so the fourth commodity is selected and returns to V(3,8-w(4))=V(3,3);
There is V(3,3)=V(2,3)=4, so the third commodity is not selected. Go back to V(2,3);
And V (2,3)= V (1,3) has V(2,3)=V(1,3-w(2))+v(2)=V(1,0)+4=0+4=4, so the second commodity is selected and returns to V(1,3-w(2))=V(1,0);
V(1,0)=V(0,0)=0, so the first item was not selected.

The detailed code is as follows:

#include<iostream>
using namespace std;
#include <algorithm>
 
int w[5] = { 0 , 2 , 3 , 4 , 5 };			//Volume of goods 2, 3, 4, 5
int v[5] = { 0 , 3 , 4 , 5 , 6 };			//Value of goods 3, 4, 5, 6
int bagV = 8;					        //Backpack size
int dp[5][9] = { { 0 } };			        //Dynamic programming table
int item[5];					        //Optimal solution
 
void findMax() {					//dynamic programming
	for (int i = 1; i <= 4; i++) {
		for (int j = 1; j <= bagV; j++) {
			if (j < w[i])
				dp[i][j] = dp[i - 1][j];
			else
				dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);
		}
	}
}
 
void findWhat(int i, int j) {				//Optimal solution
	if (i >= 0) {
		if (dp[i][j] == dp[i - 1][j]) {
			item[i] = 0;
			findWhat(i - 1, j);
		}
		else if (j - w[i] >= 0 && dp[i][j] == dp[i - 1][j - w[i]] + v[i]) {
			item[i] = 1;
			findWhat(i - 1, j - w[i]);
		}
	}
}
 
void print() {
	for (int i = 0; i < 5; i++) {			//Dynamic programming table output
		for (int j = 0; j < 9; j++) {
			cout << dp[i][j] << ' ';
		}
		cout << endl;
	}
	cout << endl;
 
	for (int i = 0; i < 5; i++)			//Optimal solution output
		cout << item[i] << ' ';
	cout << endl;
}
 
int main()
{
	findMax();
	findWhat(4, 8);
	print();
 
	return 0;
}

Longest increasing subsequence problem

Idea:

  1. Define the meaning of dp. For example, dp is an array. dp[i] represents the length of the longest increasing subsequence in v[0... I] when it is determined that v[i] must be selected.
  2. Write recursive or state transition equation: dp[i] = max(dp[j]) + 1 when v [i] > v [J]
  3. Define the optimal value, where the optimal value may be one of dp. For example, LISLength = max(dp[i])

Example:
Calculate the minimum number of students so that the remaining students form a chorus line

explain:

N students stand in a row, and the music teacher will ask (N-K) students to stand out, so that the remaining K students form a chorus line.
Chorus formation refers to such a formation: let K students number 1, 2,..., K from left to right, and their heights are T1, T2,..., TK respectively, then their heights meet the existence of i (1 < = i < = k) so that T1 < T2 <... < ti-1ti + 1 >... > TK.

Your task is to know the height of all N students, and calculate at least a few students, so that the remaining students can form a chorus formation.

Note: it is not allowed to change the order of queue elements, and it is not required that the number of the highest students must be equal
Please pay attention to processing multiple sets of input and output!

remarks:
1<=N<=3000
Enter Description:
There are multiple groups of use cases, and each group contains two lines of data. The first line is the total number of students N, and the second line is the height of N students, separated by spaces

Output Description:
At least a few students are needed

Example 1
Input:
8
186 186 150 200 160 130 197 200
copy
Output:
4

Solution:
The core problem is the longest increasing subsequence, which can be understood by referring to the longest increasing subsequence of leetcode.

In general, it is to find the optimal value dp array of the longest increasing subsequence from left to right, and the optimal value dp array of the longest decreasing subsequence from right to left. The two are added by - 1. The maximum value is the maximum number of people left on the field by the whole chorus, so it is the minimum value of out of line.

#include<iostream>
#include<vector>
using namespace std;

int main()
{
    int n;
    while(cin >> n){
        // Input array
        int tmp;
        vector<int> v;
        for (int i = 0; i < n; ++i){
            cin >>tmp;
            v.push_back(tmp);
        }

        // Longest increasing subsequence
        if (v.empty()) return 0;
        vector<int> dp1(n, 0);
        for (int i = 0; i < n; ++i){
            dp1[i] = 1;
            for(int j = 0; j <  i ; ++j){
                if (v[i] > v[j]){
                    dp1[i] = max(dp1[i], dp1[j]+1);
                }
            }
        }

        // Longest decreasing subsequence
        vector<int> dp2(n, 0);
        for (int i = n - 1; i >= 0; --i){
            dp2[i] = 1;
            for (int j = n -1; j > i; --j){
                if (v[i] > v[j]){
                    dp2[i] = max(dp2[i], dp2[j]+1);
                }
            }
        }


        int maxLength = 0;
        for (int  i = 0; i < n; ++i){
            if (maxLength < dp1[i] + dp2[i] - 1){
                maxLength = dp1[i] + dp2[i] - 1;
                //i here is the midpoint of the division
            }
        }
        cout << n - maxLength << endl;
    }
    return 0;
}

Posted by wata on Thu, 07 Oct 2021 14:40:22 -0700