整理几个非常基础的线性dp基础题:
1.
Description
A military contractor for the Department of Defense has just completed a series of preliminary tests for a new defensive missile called the CATCHER which is capable of intercepting multiple incoming offensive missiles. The CATCHER is supposed to be a remarkable defensive missile. It can move forward, laterally, and downward at very fast speeds, and it can intercept an offensive missile without being damaged. But it does have one major flaw. Although it can be fired to reach any initial elevation, it has no power to move higher than the last missile that it has intercepted.
The tests which the contractor completed were computer simulations of battlefield and hostile attack conditions. Since they were only preliminary, the simulations tested only the CATCHER's vertical movement capability. In each simulation, the CATCHER was fired at a sequence of offensive missiles which were incoming at fixed time intervals. The only information available to the CATCHER for each incoming missile was its height at the point it could be intercepted and where it appeared in the sequence of missiles. Each incoming missile for a test run is represented in the sequence only once.
The result of each test is reported as the sequence of incoming missiles and the total number of those missiles that are intercepted by the CATCHER in that test.
The General Accounting Office wants to be sure that the simulation test results submitted by the military contractor are attainable, given the constraints of the CATCHER. You must write a program that takes input data representing the pattern of incoming missiles for several different tests and outputs the maximum numbers of missiles that the CATCHER can intercept for those tests. For any incoming missile in a test, the CATCHER is able to intercept it if and only if it satisfies one of these two conditions:
The incoming missile is the first missile to be intercepted in this test.
-or-
The missile was fired after the last missile that was intercepted and it is not higher than the last missile which was intercepted.
The tests which the contractor completed were computer simulations of battlefield and hostile attack conditions. Since they were only preliminary, the simulations tested only the CATCHER's vertical movement capability. In each simulation, the CATCHER was fired at a sequence of offensive missiles which were incoming at fixed time intervals. The only information available to the CATCHER for each incoming missile was its height at the point it could be intercepted and where it appeared in the sequence of missiles. Each incoming missile for a test run is represented in the sequence only once.
The result of each test is reported as the sequence of incoming missiles and the total number of those missiles that are intercepted by the CATCHER in that test.
The General Accounting Office wants to be sure that the simulation test results submitted by the military contractor are attainable, given the constraints of the CATCHER. You must write a program that takes input data representing the pattern of incoming missiles for several different tests and outputs the maximum numbers of missiles that the CATCHER can intercept for those tests. For any incoming missile in a test, the CATCHER is able to intercept it if and only if it satisfies one of these two conditions:
The incoming missile is the first missile to be intercepted in this test.
-or-
The missile was fired after the last missile that was intercepted and it is not higher than the last missile which was intercepted.
Input
The input data for any test consists of a sequence of one or more non-negative integers, all of which are less than or equal to 32,767, representing the heights of the incoming missiles (the test pattern). The last number in each sequence is -1, which signifies the end of data for that particular test and is not considered to represent a missile height. The end of data for the entire input is the number -1 as the first value in a test; it is not considered to be a separate test.
Output
Output for each test consists of a test number (Test #1, Test #2, etc.) and the maximum number of incoming missiles that the CATCHER could possibly intercept for the test. That maximum number appears after an identifying message. There must be at least one blank line between output for successive data sets.
Note: The number of missiles for any given test is not limited. If your solution is based on an inefficient algorithm, it may not execute in the allotted time.
Note: The number of missiles for any given test is not limited. If your solution is based on an inefficient algorithm, it may not execute in the allotted time.
Sample Input
389 207 155 300 299 170 158 65 -1 23 34 21 -1 -1
Sample Output
Test #1: maximum possible interceptions: 6 Test #2: maximum possible interceptions: 2
题目这么长,实际上要求最长不增序列的长度,本题的输入输出也要注意
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
#include <vector>
int tt, s, i;
vector<int> a(100005), dp(100005);//存储不定长度数组
// dp[i]表示,前i个数组成的序列中,最长的非增序列的长度
// 转移方程 ( 0 <= k < j )
// if (a[j] < a[k] && dp[j] <= dp[k]) dp[j] = 1 + dp[k];
void solve()
{
int n = i + 1; dp[0] = 1;
for (int j = 1; j < n; j++)
{
dp[j] = 1;
for (int k = 0; k < j; k++)
{
if (a[j] < a[k] && dp[j] <= dp[k]) dp[j] = dp[k] + 1;
}
}
int ans = 0;
for (int j = 0; j < n; j++)
ans=max(ans, dp[j]);
printf("Test #%d:\n", ++tt);
printf(" maximum possible interceptions: %d\n\n", ans);
}
int main()
{
while (~scanf("%d", &s) && s != -1)
{
i = 0; a[0] = s;
while (~scanf("%d", &s) && s != -1)
a[++i] = s;
solve();
}
return 0;
}
Description
7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 (Figure 1)
Input
Your program is to read from standard input. The first line contains one integer N: the number of rows in the triangle. The following N lines describe the data of the triangle. The number of rows in the triangle is > 1 but <= 100. The numbers in the triangle, all integers, are between 0 and 99.
Output
Your program is to write to standard output. The highest sum is written as an integer.
Sample Input
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
Sample Output
30
求一个n行的如下三角形,从第一行开始,向下,或向右下加数,求其最大值
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int64;
const int MaxN = 105;
int n, a[MaxN][MaxN], dp[MaxN][MaxN];
// dp[i][j]表示,走到(i, j)时的最大值
// 转移方程
// dp[i][j] = a[i][j] + max(dp[i - 1][j], dp[i - 1][j - 1])
void solve()
{
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
scanf("%d", &a[i][j]);
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
{
int t1 = 0, t2 = 0;
if (i - 1 >= 0) t1 = dp[i - 1][j];
if (i - 1 >= 0 && j - 1 >= 0) t2 = dp[i - 1][j - 1];//注意边界不能溢出
dp[i][j] = max(t1, t2) + a[i][j];
}
int ans = 0;
for (int j = 0; j < n; j++)
ans=max(ans, dp[n - 1][j]);
printf("%d\n", ans);
}
int main()
{
while (~scanf("%d", &n)) solve();
return 0;
}
3.
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
求解最长公共子序列长度
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int64;
const int MaxL = 1005;
string a, b;
int dp[MaxL][MaxL];
// 最长公共子子串LCS
// dp[i][j]表示,分别到a[i]和b[j]结束的串,最长公共子串的长度
// 转移方程:相同则加1,不同则取最大的
// if (a[i] == b[j]) dp[i][j] = dp[i - 1][j - 1] + 1;
// else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
void solve()
{
int n = a.size(), m = b.size();
int tmp = max(n, m);
for (int i = 0; i <= tmp; i++)
dp[i][0] = dp[0][i] = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
dp[i][j] = 0;
if (a[i - 1] == b[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
else dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
}
int ans = dp[n][m];
printf("%d\n", ans);
}
int main()
{
while (cin >> a >> b) solve();
return 0;
}
4.
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
求一个连续子序列其和最大,并记录序列的开头和结尾的序号:
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int64;
const int MaxN = 100005;
int a[MaxN], dp[MaxN];
int t, tt, n, s, e;
int ans, fs, fe;
// 最大子串和
// dp[i]表示到第i个数以i为结尾的子串(包括第i个)的最大值
// 转移方程:判断是添加一个数后更大,还是另外新开一个更大
// dp[i] = max(dp[i - 1] + a[i], a[i])
// ans = max{dp[i]};
// 当新开一个时(也就是a[i] > dp[i - 1] + a[i]时),更新左节点
// 否则,更新右节点
void solve()
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
s = e = 0; dp[0] = a[0];
ans = a[0]; fs = fe = 0;
for (int i = 1; i < n; i++)
{
if (dp[i - 1] + a[i] >= a[i])
dp[i] = dp[i - 1] + a[i], e = i;
else dp[i] = a[i], s = e = i;
if (ans < dp[i])
ans = dp[i], fs = s, fe = e;
}
printf("Case %d:\n", ++tt);
printf("%d %d %d\n", ans, fs + 1, fe + 1);//难点在于对开始与结尾的数的序号的确定。
if (t) puts("");
}
int main()
{
scanf("%d", &t);
while (t--) solve();
return 0;
}
5.
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long int64;
const int MaxL = 105;
int dp[MaxL][MaxL], grid[MaxL][MaxL];
int n, m;
// 最长下降的路
// dp[i][j]表示到节点(i, j)的最大值
// 转移方程:判断四个方向哪一个满足条件并且更大即可
// dp[i][j] = max(dp[i - 1][j] + 1, dp[i + 1][j] + 1,
// dp[i][j - 1] + 1, dp[i][j + 1] + 1);
// ans = max{dp[i][j]};
// 利用记忆化搜索进行处理,这样可以减少计算
int dfs(int x, int y)
{
if (dp[x][y] != 0) return dp[x][y];
dp[x][y] = 1;
if ((grid[x - 1][y] < grid[x][y]) && (x >= 1))
dp[x][y] = max(dp[x][y], dfs(x - 1, y) + 1);
if ((grid[x + 1][y] < grid[x][y]) && (x + 1 < n))
dp[x][y] = max(dp[x][y], dfs(x + 1, y) + 1);
if ((grid[x][y - 1] < grid[x][y]) && (y >= 1))
dp[x][y] = max(dp[x][y], dfs(x, y - 1) + 1);
if ((grid[x][y + 1] < grid[x][y]) && (y + 1 < m))
dp[x][y] = max(dp[x][y], dfs(x, y + 1) + 1);
return dp[x][y];
}
void solve()
{
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
scanf("%d", &grid[i][j]);
memset(dp, false, sizeof(dp));
int ans = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
ans=max(ans, dfs(i, j));
printf("%d\n", ans);
}
int main()
{
while (~scanf("%d%d", &n, &m)) solve();
return 0;
}
6.
Description
You want to arrange the window of your flower shop in a most pleasant way. You have F bunches of flowers, each being of a different kind, and at least as many vases ordered in a row. The vases are glued onto the shelf and are numbered consecutively 1 through V, where V is the number of vases, from left to right so that the vase 1 is the leftmost, and the vase V is the rightmost vase. The bunches are moveable and are uniquely identified by integers between 1 and F. These id-numbers have a significance: They determine the required order of appearance of the flower bunches in the row of vases so that the bunch i must be in a vase to the left of the vase containing bunch j whenever i < j. Suppose, for example, you have bunch of azaleas (id-number=1), a bunch of begonias (id-number=2) and a bunch of carnations (id-number=3). Now, all the bunches must be put into the vases keeping their id-numbers in order. The bunch of azaleas must be in a vase to the left of begonias, and the bunch of begonias must be in a vase to the left of carnations. If there are more vases than bunches of flowers then the excess will be left empty. A vase can hold only one bunch of flowers.
Each vase has a distinct characteristic (just like flowers do). Hence, putting a bunch of flowers in a vase results in a certain aesthetic value, expressed by an integer. The aesthetic values are presented in a table as shown below. Leaving a vase empty has an aesthetic value of 0.
According to the table, azaleas, for example, would look great in vase 2, but they would look awful in vase 4.
To achieve the most pleasant effect you have to maximize the sum of aesthetic values for the arrangement while keeping the required ordering of the flowers. If more than one arrangement has the maximal sum value, any one of them will be acceptable. You have to produce exactly one arrangement.
Each vase has a distinct characteristic (just like flowers do). Hence, putting a bunch of flowers in a vase results in a certain aesthetic value, expressed by an integer. The aesthetic values are presented in a table as shown below. Leaving a vase empty has an aesthetic value of 0.
V A S E S | ||||||
1 | 2 | 3 | 4 | 5 | ||
Bunches | 1 (azaleas) | 7 | 23 | -5 | -24 | 16 |
2 (begonias) | 5 | 21 | -4 | 10 | 23 | |
3 (carnations) | -21 | 5 | -4 | -20 | 20 |
According to the table, azaleas, for example, would look great in vase 2, but they would look awful in vase 4.
To achieve the most pleasant effect you have to maximize the sum of aesthetic values for the arrangement while keeping the required ordering of the flowers. If more than one arrangement has the maximal sum value, any one of them will be acceptable. You have to produce exactly one arrangement.
Input
- The first line contains two numbers: F, V.
- The following F lines: Each of these lines contains V integers, so that Aij is given as the jth number on the (i+1)st line of the input file.
- 1 <= F <= 100 where F is the number of the bunches of flowers. The bunches are numbered 1 through F.
- F <= V <= 100 where V is the number of vases.
- -50 <= Aij <= 50 where Aij is the aesthetic value obtained by putting the flower bunch i into the vase j.
Output
The first line will contain the sum of aesthetic values for your arrangement.
Sample Input
3 5 7 23 -5 -24 16 5 21 -4 10 23 -21 5 -4 -20 20
Sample Output
53
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">
</span>
<span style="font-family: Arial, Helvetica, sans-serif;">#include <cmath></span>
#include <cstdio>
#include <string>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <algorithm>
using namespace std;
const int MaxN = 105;
const int INF = 100000;
int f, v;
int a[MaxN][MaxN], dp[MaxN][MaxN];
// dp[i][j]表示前i束花插入到前j个花瓶里所产生的最大的美学价值
// 转移方程:当j小于i时,连续赋值;超过之后,判断是否添加新的花即可
// (j <= i): dp[i][j] = dp[i - 1][j - 1] + a[i][j];
// (j > i ): dp[i][j] = max(dp[i - 1][j - 1] + a[i][j], dp[i][j - 1])
void solve()
{
for (int i = 1; i <= f; i++)
for (int j = 1; j <= v; j++)
scanf("%d", &a[i][j]);
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= f; i++)
for (int j = 0; j <= v; j++)// 初值设置
dp[i][j] = -INF;
for (int i = 1; i <= f; i++)
for (int j = i; j <= v - f + i; j++)
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j - 1] + a[i][j]);
printf("%d\n", dp[f][v]);
}
int main()
{
while (~scanf("%d%d", &f, &v)) solve();
return 0;
}