您的位置:首页 > 其它

线性dp<一>

2014-07-26 17:52 246 查看
整理几个非常基础的线性dp基础题:

1.

简单dp 例题
Time Limit:1000MS Memory Limit:30000KB 64bit IO Format:%I64d
& %I64u
Submit Status Practice POJ
1887

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.

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.

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


2.

简单dp 例题
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d
& %I64u
Submit Status Practice POJ
1163

Description

7
3   8
8   1   0
2   7   4   4
4   5   2   6   5

(Figure 1)


Figure 1 shows a number triangle. Write a program that calculates the highest sum of numbers passed on a route that starts at the top and ends somewhere on the base. Each step can go either diagonally down to the left or diagonally down to the right.

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.

简单dp 例题
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d
& %I64u
Submit Status Practice POJ
1458

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
[m];
    printf("%d\n", ans);
}

int main()
{
    while (cin >> a >> b) solve();
    return 0;
}


4.

简单dp 例题
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d
& %I64u
Submit Status Practice HDU
1003

Description

Given a sequence a[1],a[2],a[3]......a
, 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.

简单dp 例题
Time Limit:1000MS Memory Limit:65536KB 64bit IO Format:%I64d
& %I64u
Submit Status Practice POJ
1088

Description

Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长底滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子

1  2  3  4 5 
16 17 18 19 6 
15 24 25 20 7 
14 23 22 21 8 
13 12 11 10 9


一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。

Input

输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。

Output

输出最长区域的长度。

Sample Input

5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9


Sample Output

25


#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.

简单dp
Time Limit:1000MS Memory Limit:10000KB 64bit IO Format:%I64d
& %I64u
Submit Status Practice POJ
1157

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.

V A S E S
1
2
3
4
5
Bunches
1 (azaleas)
723-5-2416
2 (begonias)
521-41023
3 (carnations)
-21
5-4-2020
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: