Sequence DP

table of Contents

1. The general formula of the sequence DP

1. The DP problem of singular columns

2. DP problem of even series

3. The DP problem of the majority column

2. The longest ascending subsequence

CSU 1047: longest ascending subsequence

CSU 1225: ACM team queue

POJ 2533 Longest Ordered Subsequence

OpenJ_Bailian-2945 interceptor missile (the longest descending sub-sequence)

Three, the largest sub-segment and

HDU 1003 NBUT 1090 Max Sum

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

Six, super-maximum field and

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:

Description

  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.

Input

  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.

Output

 Each group of data outputs one line, the length of the longest ascending subsequence.

Sample Input

7
1 5 3 6 9 8 10

Sample Output

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;
}

 

Guess you like

Origin blog.csdn.net/nameofcsdn/article/details/112771904