算法3:动态规划(一)——简单动规

写在前面:本文记录一些简单动态规划的练习题,欢迎讨论!本系列系本人原创,如需转载或引用,请注明原作者及文章出处。本文持续更新。

一、The Triangle (POJ1163)
描述
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.
输入
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.
输出
Your program is to write to standard output. The highest sum is written as an integer.
样例输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
30
代码
#include<iostream>
#include<algorithm>
using namespace std;
int n, a[110][110], dp[110][110];

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j <= i; j++)
		{
			cin >> a[i][j];
		}
	}

	for (int i = n - 1; i >= 0; i--)
	{
		for (int j = 0; j <= i; j++)
		{
			if (i == n - 1)
			{
				dp[i][j] = a[i][j];
				continue;
			}
			dp[i][j] = a[i][j] + max(dp[i + 1][j], dp[i + 1][j + 1]);
		}
	}

	cout << dp[0][0] << endl;
	return 0;
}


二、滑雪 (POJ1088)
描述
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更长。事实上,这是最长的一条。
输入
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。
输出
输出最长区域的长度。
样例输入
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
样例输出
25
代码
#include<iostream>
#include<algorithm>
using namespace std;
int r, c, a[110][110], dp[110][110], ans;

void dfs(int x, int y)
{
	if ((x == 0 || a[x][y] <= a[x - 1][y]) && (x == r - 1 || a[x][y] <= a[x + 1][y]) && (y == 0 || a[x][y] <= a[x][y - 1]) && (y == c - 1 || a[x][y] <= a[x][y + 1]))
	{
		dp[x][y] = 1;
		return;
	}

	if (x > 0 && a[x][y] > a[x - 1][y])
	{
		if (dp[x - 1][y] == -1)
			dfs(x - 1, y);
		dp[x][y] = max(dp[x][y], dp[x - 1][y] + 1);
	}

	if (x < r - 1 && a[x][y] > a[x + 1][y])
	{
		if (dp[x + 1][y] == -1)
			dfs(x + 1, y);
		dp[x][y] = max(dp[x][y], dp[x + 1][y] + 1);
	}

	if (y > 0 && a[x][y] > a[x][y - 1])
	{
		if (dp[x][y - 1] == -1)
			dfs(x, y - 1);
		dp[x][y] = max(dp[x][y], dp[x][y - 1] + 1);
	}

	if (y < c - 1 && a[x][y] > a[x][y + 1])
	{
		if (dp[x][y + 1] == -1)
			dfs(x, y + 1);
		dp[x][y] = max(dp[x][y], dp[x][y + 1] + 1);
	}
}

int main()
{
	cin >> r >> c;
	ans = -999999;

	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
		{
			cin >> a[i][j];
			dp[i][j] = -1;
		}

	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			dfs(i, j);

	for (int i = 0; i < r; i++)
		for (int j = 0; j < c; j++)
			ans = max(ans, dp[i][j]);

	cout << ans << endl;
	return 0;
}


三、To the Max (POJ1050)
描述
Given a two-dimensional array of positive and negative integers, a sub-rectangle is any contiguous sub-array of size 1*1 or greater located within the whole array. The sum of a rectangle is the sum of all the elements in that rectangle. In this problem the sub-rectangle with the largest sum is referred to as the maximal sub-rectangle.
As an example, the maximal sub-rectangle of the array:

0 -2 -7 0
9 2 -6 2
-4 1 -4 1
-1 8 0 -2
is in the lower left corner:

9 2
-4 1
-1 8
and has a sum of 15.
输入
The input consists of an N * N array of integers. The input begins with a single positive integer N on a line by itself, indicating the size of the square two-dimensional array. This is followed by N^2 integers separated by whitespace (spaces and newlines). These are the N^2 integers of the array, presented in row-major order. That is, all numbers in the first row, left to right, then all numbers in the second row, left to right, etc. N may be as large as 500. The numbers in the array will be in the range [-127,127].
输出
Output the sum of the maximal sub-rectangle.
样例输入
4 0 -2 -7 0 9 2 -6 2 -4 1 -4 1 -18 0 -2 样例输出
15 代码
#include<iostream>
#include<algorithm>
using namespace std;
int n, a[510][510], temp[510], maxt, maxsum;

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			cin >> a[i][j];

	maxsum = -999999;
	for (int i = 0; i < n; i++)
	{
		for (int k = 0; k < n; k++)
		{
			temp[k] = 0;
		}

		for (int j = i; j < n; j++)
		{
			for (int k = 0; k < n; k++)
			{
				temp[k] += a[j][k];
			}

			maxt = 0;
			for (int k = 0; k < n; k++)
			{
				maxt += temp[k];
				maxsum = max(maxsum, maxt);
				maxt = max(maxt, 0);
			}
		}
	}

	cout << maxsum << endl;
	return 0;
}

四、Maximum sum (POJ2479)
描述
Given a set of n integers: A={a1, a2,..., an}, we define a function d(A) as below:
                     t1     t2 
         d(A) = max{ ∑ai + ∑aj | 1 <= s1 <= t1 < s2 <= t2 <= n }
                    i=s1   j=s2

Your task is to calculate d(A).
输入
The input consists of T(<=30) test cases. The number of test cases (T) is given in the first line of the input.
Each test case contains two lines. The first line is an integer n(2<=n<=50000). The second line contains n integers: a1, a2, ..., an. (|ai| <= 10000).There is an empty line after each case.
输出
Print exactly one line for each test case. The line should contain the integer d(A).
样例输入
1
10 1 -1 2 2 3 -3 4 -4 5 -5 样例输出
13
代码
#include<iostream>
#include<algorithm>
using namespace std;
int T, n, a[50010], f[50010], f2[50010], maxt, maxsum, ans;

int main()
{
	cin >> T;
	for (int t = 0; t < T; t++)
	{
		cin >> n;
		for (int i = 0; i < n; i++)
		{
			cin >> a[i];
			f[i] = 0;
		}

		maxt = 0;
		maxsum = -999999;
		ans = -999999;

		for (int i = 0; i < n; i++)
		{
			maxt += a[i];
			maxsum = max(maxsum, maxt);
			f[i] = maxsum;
			maxt = max(maxt, 0);
		}

		f2[0] = -999999;
		f2[1] = a[0] + a[1];
		for (int i = 2; i < n; i++)
			f2[i] = a[i] + max(f[i - 1], f2[i - 1]);

		for (int i = 0; i < n; i++)
			ans = max(ans, f2[i]);

		cout << ans << endl;
	}
	return 0;
}


五、BUY LOW, BUY LOWER (POJ1952)
描述
The advice to "buy low" is half the formula to success in the bovine stock market.To be considered a great investor you must also follow this problems' advice:
                    "Buy low; buy lower"

Each time you buy a stock, you must purchase it at a lower price than the previous time you bought it. The more times you buy at a lower price than before, the better! Your goal is to see how many times you can continue purchasing at ever lower prices.

You will be given the daily selling prices of a stock (positive 16-bit integers) over a period of time. You can choose to buy stock on any of the days. Each time you choose to buy, the price must be strictly lower than the previous time you bought stock. Write a program which identifies which days you should buy stock in order to maximize the number of times you buy.

Here is a list of stock prices:
 Day   1  2  3  4  5  6  7  8  9 10 11 12
Price 68 69 54 64 68 64 70 67 78 62 98 87

The best investor (by this problem, anyway) can buy at most four times if each purchase is lower then the previous purchase. One four day sequence (there might be others) of acceptable buys is:
Day    2  5  6 10
Price 69 68 64 62
输入
* Line 1: N (1 <= N <= 5000), the number of days for which stock prices are given

* Lines 2..etc: A series of N space-separated integers, ten per line except the final line which might have fewer integers.
输出
Two integers on a single line:
* The length of the longest sequence of decreasing prices
* The number of sequences that have this length (guaranteed to fit in 31 bits)
In counting the number of solutions, two potential solutions are considered the same (and would only count as one solution) if they repeat the same string of decreasing prices, that is, if they "look the same" when the successive prices are compared. Thus, two different sequence of "buy" days could produce the same string of decreasing prices and be counted as only a single solution.
样例输入 12 68 69 54 64 68 64 70 67 78 6298 87 样例输出 4 2

代码

#include<iostream>
#include<algorithm>
using namespace std;
int n, a[5010], f[5010], g[5010], maxf, maxg;

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> a[i];
		f[i] = 1;
	}

	for (int i = 1; i < n; i++)
	{
		for (int j = 0; j < i; j++)
		{
			if (a[j] > a[i])
			{
				f[i] = max(f[i], f[j] + 1);
			}
		}
	}

	for (int i = 0; i < n; i++)
	{
		if (f[i] == 1)
			g[i] = 1;
		else
			g[i] = 0;

		for (int j = 0; j < i; j++)
		{
			if (f[j] + 1 == f[i] && a[j] > a[i])
			{
				g[i] += g[j];
			}

			if (a[i] == a[j] && f[i] == f[j])
				g[j] = 0;
		}
	}

	maxf = -999999;
	maxg = 0;

	for (int i = 0; i < n; i++)
	{
		maxf = max(maxf, f[i]);
	}

	for (int i = 0; i < n; i++)
	{
		if (maxf == f[i])
			maxg += g[i];
	}

	cout << maxf << " " << maxg << endl;
	return 0;
}


六、股票买卖 (POJ8464)
描述 最近越来越多的人都投身股市,阿福也有点心动了。谨记着“股市有风险,入市需谨慎”,阿福决定先来研究一下简化版的股票买卖问题。 假设阿福已经准确预测出了某只股票在未来 N 天的价格,他希望买卖两次,使得获得的利润最高。为了计算简单起见,利润的计算方式为卖出的价格减去买入的价格。 同一天可以进行多次买卖。但是在第一次买入之后,必须要先卖出,然后才可以第二次买入。 现在,阿福想知道他最多可以获得多少利润。
输入
输入的第一行是一个整数 T (T <= 50) ,表示一共有 T 组数据。
接下来的每组数据,第一行是一个整数 N (1 <= N <= 100, 000) ,表示一共有 N 天。第二行是 N 个被空格分开的整数,表示每天该股票的价格。该股票每天的价格的绝对值均不会超过 1,000,000 。
输出
对于每组数据,输出一行。该行包含一个整数,表示阿福能够获得的最大的利润。
样例输入 3 7
5 14 -2 4 9 3 17
6
6 8 7 4 1 -2
4
18 9 5 2
样例输出
28
2
0
提示 对于第一组样例,阿福可以第 1 次在第 1 天买入(价格为 5 ),然后在第 2 天卖出(价格为 14 )。第 2 次在第 3 天买入(价格为-2 ),然后在第 7 天卖出(价格为 17 )。一共获得的利润是 (14 - 5) + (17 - (-2)) = 28 对于第二组样例,阿福可以第 1 次在第 1 天买入(价格为 6 ),然后在第 2 天卖出(价格为 8 )。第 2 次仍然在第 2 天买入,然后在第 2 天卖出。一共获得的利润是 8 - 6 = 2
对于第三组样例,由于价格一直在下跌,阿福可以随便选择一天买入之后迅速卖出。获得的最大利润为 0
代码
#include<iostream>
#include<algorithm>
using namespace std;
int T, n, a[100010], f1[100010], f2[100010], mina, maxa, temp, maxLRleft, maxLRright, res; //f1 is forward dp, f2 is backward dp.

int main()
{
	scanf("%d", &T);
	for (int t = 0; t < T; t++)
	{
		scanf("%d", &n);
		for (int i = 0; i < n; i++)
			scanf("%d", &a[i]);

		maxLRleft = -999999;
		maxLRright = -999999;
		res = 0;
		f1[0] = 0;
		f2[n - 1] = 0;
		mina = a[0];
		maxa = a[n - 1];

		for (int i = 1; i < n; i++)
		{
			mina = min(mina, a[i]);
			temp = a[i] - mina;
			maxLRleft = max(maxLRleft, temp);
			f1[i] = maxLRleft;
		}

		for (int i = n - 2; i >= 0; i--)
		{
			maxa = max(maxa, a[i]);
			temp = maxa - a[i];
			maxLRright = max(maxLRright, temp);
			f2[i] = maxLRright;
		}
		
		for (int i = 0; i < n;i++)
			res = max(res, f1[i] + f2[i]);

		cout << res << endl;
	}
	return 0;
}



猜你喜欢

转载自blog.csdn.net/qq_24574309/article/details/54312867