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).
-
Establish the model, that is, find max(V1X1+V2X2 +... + VnXn);
-
Find constraints, W1X1+W2X2 +... + wnxn < capacity;
-
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:
- 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.
- Write recursive or state transition equation: dp[i] = max(dp[j]) + 1 when v [i] > v [J]
- 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; }