table of Contents
1. The general formula of the sequence DP
1. The DP problem of singular columns
3. The DP problem of the majority column
2. The longest ascending subsequence
CSU 1047: longest ascending subsequence
POJ 2533 Longest Ordered Subsequence
OpenJ_Bailian-2945 interceptor missile (the longest descending sub-sequence)
Three, the largest sub-segment and
Fourth, the (longest) common subsequence
HDOJ 5791 Two (the number of common subsequences)
POJ 1458 Common Subsequence (the longest common subsequence)
CSU-1060 Nearest Sequence (the longest common subsequence of three arrays)
Five, super-increasing sequence
CSU - 1203 Super-increasing sequence
HDU - 1244 Max Sum Plus Plus Plus
1. The general formula of the sequence DP
1. The DP problem of singular columns
General term formula: f(n) = g(f(nc), n), where c is a constant, generally 1 or 2. g may contain other non-constant information that has nothing to do with n, such as g(f(n -1), n) = f(n-1) + array[n] + n^2, which contains the information of array.
2. DP problem of even series
General formula: f(a,b) = g(f(a,b-c1), f(a-c2,b), f(a-c3,b-c4), a, b), generally c1= c2=c3=c4=1
3. The DP problem of the majority column
The form is consistent with the general formula of the DP problem of even number series.
2. The longest ascending subsequence
CSU 1047: longest ascending subsequence
topic:
Glossary:
A string of numbers such as 1, 5, 3, 6, 9, 8, 10, its subsequence is a number of non-contiguous numbers from left to right, such as 1, 5, 6, 3, 9, 8, 10 are all Its subsequence.
The longest ascending subsequence is the longest ascending subsequence strictly increasing from left to right, and 1, 5, 6, 9, and 10 are the longest ascending subsequences of this sequence.
Given several sequences, find the length of the longest ascending subsequence of each sequence.
Multiple sets of data, each set is a positive integer n in the first line, 1 <= n <= 1000, and a positive integer not greater than 1,000,000 separated by n spaces in the second line.
Each group of data outputs one line, the length of the longest ascending subsequence.
7
1 5 3 6 9 8 10
5
Code:
#include<iostream>
using namespace std;
int main()
{
int k, h[1001], ans[1001];
while(cin >> k)
{
for (int i = 0; i < k; i++)cin >> h[i];
ans[0] = 1;
for (int i = 1; i < k; i++)
{
ans[i] = 1;
for (int j = 0; j < i; j++)
if (h[j] < h[i] && ans[i] < ans[j] + 1)ans[i] = ans[j] + 1;
}
int m = 0;
for (int i = 0; i < k; i++)if (m < ans[i])m = ans[i];
cout << m << endl;
}
return 0;
}
CSU 1225: ACM team queue
topic:
Description
The ACM team has to line up every time they go out for an event, but everyone does not want to arrange the team according to any rules (probably because everyone has a personality, such as Gestapolur), so every time the team is chaotic, but Samsara today Suddenly I want to calculate the longest sub-queue in ascending order of height in the team, and also want to know the number of the longest sub-queue. The so-called sub-queue is a queue A_p[1]...A_p[2]..A_p[m],(1<=p[1]<p[2 in queue A_1...A_i...A_n ]<...& lt;p[m]<=n,m<=n). Samsara's statistics are very bad, so you have to trouble you who can program to help him solve this problem.
Input
There are two rows of data in each group. The first row has a positive integer n (1<=n<=1000), which means there are n people. The second row has n positive integers separated by spaces A_1...A_i..A_n(1 <=A_i<=200), which means the height of these n people.
Output
There are also several lines in the output. Please output the length and number of the longest sub-queue that meets the requirements, separated by spaces.
Sample Input
5
1 4 2 6 3
Sample Output
3 3
Code:
#include<iostream>
using namespace std;
int main()
{
int k, h[1001], len[1001], num[1001];
while (cin >> k)
{
for (int i = 0; i < k; i++)cin >> h[i];
len[0] = 1, num[0] = 1;
for (int i = 1; i < k; i++)
{
len[i] = 1, num[i] = 1;
for (int j = 0; j < i; j++)if (h[j] < h[i])
{
if (len[i] < len[j] + 1)len[i] = len[j] + 1, num[i] = num[j];
else if (len[i] == len[j] + 1)num[i] += num[j];
}
}
int m = 0, ans = 0;
for (int i = 0; i < k; i++)if (m < len[i])m = len[i], ans = num[i];
else if (m == len[i])ans += num[i];
cout << m << " " << ans << endl;
}
return 0;
}
POJ 2533 Longest Ordered Subsequence
topic:
Description
A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence ( a1, a2, ..., aN) be any sequence ( ai1, ai2, ..., aiK), where 1 <= i1 < i2 < ... < iK <= N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).
Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.
Input
The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000
Output
Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.
Sample Input
7
1 7 3 5 9 4 8
Sample Output
4
Let maxs[i] represent the length of the longest increasing subsequence ending with the i-th number. (Originally, max was used, but there was a name conflict, so s was added)
There is no big problem with this topic. There is only one place to pay attention to. If a number is smaller than all the previous numbers, then the following two-layer for loop does not modify maxs.
So the initialization of maxs should be all initialized to 1.
Code:
#include<iostream>
using namespace std;
int list[1000];
int maxs[1000];
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> list[i];
maxs[i] = 1;
}
for (int i = 1; i < n; i++)for (int j = 0; j < i; j++)
if (list[j] < list[i] && maxs[i] < maxs[j] + 1)maxs[i] = maxs[j] + 1;
int m = 0;
for (int i = 0; i < n; i++)if (m < maxs[i])m = maxs[i];
cout << m;
return 0;
}
OpenJ_Bailian-2945 interceptor missile (the longest descending sub-sequence)
topic:
A certain country has developed a missile interception system to defend against missile attacks by the enemy. However, this missile interception system has a flaw: although its first shell can reach any height, each subsequent shell cannot be higher than the previous one. One day, the radar caught an enemy country’s missile attack and observed the heights of the missiles flying in sequence. Please calculate the maximum number of missiles this system can intercept. When intercepting incoming missiles, the time sequence of the incoming missile attacks must be followed, and it is not allowed to intercept the latter missile first, and then intercept the preceding missile.
Input
There are two lines of input, the
first line, input the number of enemy missiles captured by the radar k (k<=25), the
second line, input k positive integers, representing the height of the k missiles, according to the attack time of the incoming missile The order is given, separated by spaces.
Output
The output is only one line, containing an integer, indicating the maximum number of missiles that can be intercepted.
Sample Input
8
300 207 155 300 299 170 158 65
Sample Output
6
Code:
#include<iostream>
using namespace std;
int main()
{
int k, h[30], ans[30];
cin >> k;
for (int i = 0; i < k; i++)cin >> h[i];
ans[0] = 1;
for (int i = 1; i < k; i++)
{
ans[i] = 1;
for (int j = 0; j < i; j++)
if (h[j] >= h[i] && ans[i] < ans[j] + 1)ans[i] = ans[j] + 1;
}
int m = 0;
for (int i = 0; i < k; i++)if (m < ans[i])m = ans[i];
cout << m;
return 0;
}
Three, the largest sub-segment and
HDU 1003 NBUT 1090 Max Sum
topic:
Description
Given a sequence a[1],a[2],a[3]......a[n], your job is to calculate the max sum of a sub-sequence. For example, given (6,-1,5,4,-7), the max sum in this sequence is 6 + (-1) + 5 + 4 = 14.
Input
The first line of the input contains an integer T(1<=T<=20) which means the number of test cases. Then T lines follow, each line starts with a number N(1<=N<=100000), then N integers followed(all the integers are between -1000 and 1000).
Output
For each test case, you should output two lines. The first line is "Case #:", # means the number of the test case. The second line contains three integers, the Max Sum in the sequence, the start position of the sub-sequence, the end position of the sub-sequence. If there are more than one result, output the first one. Output a blank line between two cases.
Sample Input
2
5 6 -1 5 4 -7
7 0 6 -1 1 -6 7 -5
Sample Output
Case 1:
14 1 4
Case 2:
7 1 6
This topic is to find the largest sub-paragraph sum.
List is each number, start[i] is the starting subscript of the largest field sum ending in i.
The slight difference from the general statement is that it outputs the leftmost subsection.
There are two places to pay attention to. First, there may be multiple start subscripts for the largest field ending in i, and start[i] must be the leftmost one.
Second, even under the premise of "start[i] must be the leftmost one", there may still be many maximum field sums. In this case, the leftmost one needs to be taken.
Code:
#include<iostream>
using namespace std;
int list[100001];
int start[100001];
int main()
{
int cas;
int n;
cin >> cas;
for (int i = 1; i <= cas;i++)
{
cin >> n;
list[0] = -1;
start[1] = 1;
for (int i = 1; i <= n; i++)
{
cin >> list[i];
if (list[i - 1] >= 0)
{
list[i] += list[i - 1];
start[i] = start[i - 1];
}
else start[i] = i;
}
int maxs = list[1], key = 1;
for (int i = 2; i <= n; i++)
{
if (maxs < list[i])
{
maxs = list[i];
key = i;
}
}
cout << "Case " << i << ":" << endl << maxs << " " << start[key] << " " << key << endl;
if (i < cas)cout << endl;
}
return 0;
}
Fourth, the (longest) common subsequence
HDOJ 5791 Two (the number of common subsequences)
topic:
Description
Alice gets two sequences A and B. A easy problem comes. How many pair of sequence A' and sequence B' are same. For example, {1,2} and {1,2} are same. {1,2,4} and {1,4,2} are not same. A' is a subsequence of A. B' is a subsequence of B. The subsequnce can be not continuous. For example, {1,1,2} has 7 subsequences {1},{1},{2},{1,1},{1,2},{1,2},{1,1,2}. The answer can be very large. Output the answer mod 1000000007.
Input
The input contains multiple test cases.
For each test case, the first line cantains two integers . The next line contains N integers. The next line followed M integers. All integers are between 1 and 1000.
Output
For each test case, output the answer mod 1000000007.
Sample Input
3 2
1 2 3
2 1
3 2
1 2 3
1 2
Sample Output
2
3
For this topic, I use the list to store the n numbers, and use the variable k for the m numbers, so there is no need to store them.
At the same time, the result can be stored with only one 1-dimensional array r.
This is very similar to the 0-1 knapsack problem, because of the recursive nature, you only need to swipe r repeatedly.
Code:
#include<iostream>
#include<string.h>
using namespace std;
int n, m;
int list[1001];
int k;
int r[1001];
int main()
{
while (cin >> n >> m)
{
for (int i = 1; i <= n; i++)cin >> list[i];
cin >> k;
r[0] = 1;
for (int i = 1; i <= n; i++)
{
r[i] = r[i - 1];
if (list[i] == k)r[i]++;
}
for (int i = 1; i < m; i++)
{
cin >>k;
for (int j = n; j >0; j--)if (list[j] == k)
for (int jj = j; jj <= n; jj++)r[jj] = (r[jj] + r[j - 1]) % 1000000007;
}
cout << r[n] - 1 << endl;
}
return 0;
}
This code has a triple loop inside. Most people do this problem with a double loop (no wonder it's so fast)
The main reason is that I prepared to use only a one-dimensional array to represent the result from the beginning, which made my choice of recursion a bit complicated.
POJ 1458 Common Subsequence (the longest common subsequence)
topic:
Description
A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, x ij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
Input
The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.
Output
For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
Sample Input
abcfbc abfcab
programming contest
abcd mnp
Sample Output
4
2
0
I always overtime on this topic, and I only found out later with the help of my classmates, because the dynamic programming determines whether there is a problem with the calculation.
Wrong code:
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
char s1[1000];
char s2[1000];
int **list;
int f(int m, int n)
{
if (m < 0 || n < 0)return 0;
if (list[m][n])return list[m][n];
if (s1[m] == s2[n])
{
list[m][n] = f(m - 1, n - 1) + 1;
return list[m][n];
}
int a = f(m, n - 1);
int b = f(m - 1, n);
list[m][n] = (a>b) ? a : b;
return list[m][n];
}
int main()
{
while (scanf("%s%s", s1,s2)!=-1)
{
int a = strlen(s1);
int b = strlen(s2);
list = new int*[a];
for (int i = 0; i < a; i++)
{
list[i] = new int[b];
memset(list[i], 0, b * 4);
}
printf("%d\n", f(a - 1, b - 1));
}
return 0;
}
Because the initial value of the list is 0, the reassignment of the list after the function f is calculated may also be 0, so there is a problem.
Correct code:
#include<stdio.h>
#include <stdlib.h>
#include<string.h>
char s1[1000];
char s2[1000];
int **list;
int f(int m, int n)
{
if (m < 0 || n < 0)return 0;
if (list[m][n]!=-1)return list[m][n];
if (s1[m] == s2[n])
{
list[m][n] = f(m - 1, n - 1) + 1;
return list[m][n];
}
int a = f(m, n - 1);
int b = f(m - 1, n);
list[m][n] = (a>b) ? a : b;
return list[m][n];
}
int main()
{
while (scanf("%s%s", s1,s2)!=-1)
{
int a = strlen(s1);
int b = strlen(s2);
list = new int*[a];
for (int i = 0; i < a; i++)
{
list[i] = new int[b];
memset(list[i], -1, b * 4);
}
printf("%d\n", f(a - 1, b - 1));
}
return 0;
}
CSU-1060 Nearest Sequence (the longest common subsequence of three arrays)
topic:
Description
Do you remember the "Nearest Numbers"? Now here comes its brother:"Nearest Sequence".Given three sequences of char,tell me the length of the longest common subsequence of the three sequences.
Input
There are several test cases.For each test case,the first line gives you the first sequence,the second line gives you the second one and the third line gives you the third one.(the max length of each sequence is 100)
Output
For each test case,print only one integer :the length of the longest common subsequence of the three sequences.
Sample Input
abcd
abdc
dbca
abcd
cabd
tsc
Sample Output
2
1
Code:
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
char a[101], b[101], c[101];
int la, lb, lc;
int ans[101][101][101];
int dp(int ka, int kb, int kc)
{
if (ka < 0 || kb < 0 || kc < 0)return 0;
if (ans[ka][kb][kc] > -1)return ans[ka][kb][kc];
ans[ka][kb][kc] = max(max(dp(ka - 1, kb, kc), dp(ka, kb - 1, kc)), dp(ka, kb, kc - 1));
if (a[ka] == b[kb] && b[kb] == c[kc])ans[ka][kb][kc] = dp(ka - 1, kb - 1, kc - 1) + 1;
return ans[ka][kb][kc];
}
int main()
{
while (cin >> a >> b >> c)
{
memset(ans, -1, sizeof(ans));
cout << dp(strlen(a) - 1, strlen(b) - 1, strlen(c) - 1) << endl;
}
return 0;
}
Five, super-increasing sequence
CSU - 1203 Super-increasing sequence
topic:
Description
If any item in a sequence is greater than the sum of all the previous items, then we call this sequence a super-increasing sequence.
Now there is a sequence of integers. You can merge several adjacent items in the sequence into one item. After the merge, the value of this item is the sum of the values of the items before the merge. After merging several times, a super-increasing sequence must be finally obtained. How many items can the obtained super-increasing sequence have at most?
Input
The first line of input data contains a positive integer T (1 <= T <= 500), indicating that there will be a total of T groups of test data.
The first row of each group of test data contains an integer N (1 <= N <= 100000), indicating that there are N items in this integer sequence. The next line contains N positive integers not greater than 10000, which sequentially describe the values of each item in this sequence.
At most 10 sets of data satisfy N> 1000.
Output
For each set of test data, use one line to output an integer, indicating how many items can be in the final super-increasing sequence.
Sample Input
3
2
1 1
3
1 2 4
6
1 2 4 3 6 5
Sample Output
1
3
4
Code:
#include<iostream>
using namespace std;
int main()
{
int T;
cin >> T;
int n;
while (T--)
{
cin >> n;
int *a = new int[n + 1];
int *s = new int[n + 1];
s[0] = 0;
int *f = new int[n + 1];
f[0] = 0;
f[1] = 1;
int c[30]; //c[i]是 使得 f(x)=i的最小x
c[1] = 1;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
s[i] = s[i - 1] + a[i];
if (i > 1)
{
if (s[i] - s[c[f[i - 1]]] - s[c[f[i - 1]]] > 0)
{
f[i] = f[i - 1] + 1;
c[f[i]] = i;
}
else f[i] = f[i - 1];
}
}
cout << f[n] << endl;
}
return 0;
}
Six, super-maximum field and
HDU - 1244 Max Sum Plus Plus Plus
topic:
Description
Given an integer sequence
a1 a2 a3...an consisting of n positive integers, find the sum of
m segments of lengths l1, l2, l3...lm in the sequence of non-overlapping consecutive integers Maximum value.
Input
The first line is an integer n (0 ≤ n ≤ 1000), n = 0 means that
the first number in the second line is m (1 ≤ m ≤ 20) at the end of the input , and the
second line has m integers l1, l2...lm.
The third line is n integers a1, a2, a2...an.
Output
Output the maximum value of m-segment integer sum.
Sample Input
3
2 1 1
1 2 3
4
2 1 2
1 2 3 5
0
Sample Output
5
10
First, it is obviously dynamic programming.
This topic can be said to be an upgrade of HDU 1003 NBUT 1090 Max Sum (the maximum sub-segment sum) , and the idea is similar.
Because my code uses space compression instead of a two-dimensional array, the code is slightly more complicated.
Code:
#include<iostream>
using namespace std;
int n, m;
int list[1001], sum[1001], maxx[1001], len[20], sumlen[20];
int main()
{
while (cin >> n)
{
if (n == 0)break;
cin >> m;
for (int i = 0; i < m; i++)
{
cin >> len[i];
sumlen[i] = len[i];
if (i)sumlen[i] += sumlen[i - 1];
}
for (int i = 0; i < n; i++)
{
cin >> list[i];
sum[i] = list[i];
if (i)sum[i] += sum[i - 1];
}
for (int i = 0; i < n; i++)maxx[i] = 0;
maxx[0] = sum[len[0] - 1];
for (int j = 1; j <= n - len[0]; j++)
{
maxx[j] = sum[j + len[0] - 1] - sum[j - 1];
if (maxx[j] < maxx[j - 1])maxx[j] = maxx[j - 1];
}
for (int i = 1; i < m; i++)
{
for (int j = n - len[i]; j >= sumlen[i - 1]; j--)
maxx[j] = sum[j + len[i] - 1] - sum[j - 1] + maxx[j - len[i - 1]];
for (int j = 1; j <= n - len[i]; j++)
if (maxx[j] < maxx[j - 1])maxx[j] = maxx[j - 1];
}
if (n >= len[m - 1])cout << maxx[n - len[m - 1]] << endl;
else cout << 0 << endl;
}
return 0;
}