动态规划例题详解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44705116/article/details/102570787

1、

给出一个数字三角形:

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

从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的左边的数或者右边的数。

使用递归实现,从顶部开始,比较每个点的最大路径和,到底部开始计算;同时为了避免在计算过程中有太多的重复运算,设立一个二维数组储存每次计算后得到的最大值。

#include<iostream>
#include<vector>
#include<memory.h>
#include<stdio.h>
using namespace std;
const int maxn = 100;
int D[maxn + 10][maxn + 10];
int maxs[maxn + 10][maxn + 10];
int n;

int maxsum(int r, int j) {
	if (r == n - 1) return D[r][j];
	if (maxs[r + 1][j] == -1) {
		maxs[r + 1][j] = maxsum(r + 1, j);
	}
	if (maxs[r + 1][j + 1] == -1) {
		maxs[r + 1][j + 1] = maxsum(r + 1, j + 1);
	}
	if (maxs[r + 1][j + 1] < maxs[r + 1][j]) {
		return maxs[r+1][j] + D[r][j];
	}
	else {
		return maxs[r+1][j+1] + D[r][j];
	}
}

int main() {
	scanf_s("%d", &n);
	memset(maxs, -1, sizeof(maxs));
	for (int i = 0; i < n; i++)
		for (int j = 0; j <= i; j++) {
			scanf_s("%d", &D[i][j]);
		}
	printf("%d", maxsum(0, 0));
}

2、

输入数据
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N 个整数,这些整数的取值范围都在0 到10000。
输出要求
最长上升子序列的长度。
输入样例
7
1 7 3 5 9 4 8
输出样例
4

解这题不用递归。直接从头依次求出以每个数为结尾的最长子序列,通过比较,当前数的最长子序列长度为之前小于它的数中长度最长的子序列长度+1;

#include<iostream>
#include<vector>
#include<memory.h>
#include<stdio.h>
using namespace std;

int main() {
	int N;
	scanf_s("%d", &N);
	int b[N + 10], len[N + 10];
	for (int i = 1; i <= N; i++) {
		scanf_s("%d", &b[i]);
	}
	len[1] = 1;
	for (int i = 2; i <= N; i++) {
		int temp = 0;
		for (int j = 1; j < i; j++) {
			if (b[j] < b[i]) {
				if (temp < len[j])
					temp = len[j];
			}
		}
		len[i] = temp + 1;
	}
	int max = 0;
	for (int i = 1; i <= N; i++) {
		if (len[i] > max)
			max = len[i];
	}
	printf("%d", max);
}

3、

场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy 老鼠在时刻0 从高于所有平台的某处开始下落,它的下落速度始终为1 米/秒。当Jimmy 落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1 米/秒。当Jimmy 跑到平台的边缘时,开始继续下落。Jimmy
每次下落的高度不能超过MAX 米,不然就会摔死,游戏也会结束。
设计一个程序,计算Jimmy 到地面时可能的最早时间。
输入数据 第一行是测试数据的组数t(0 <= t <= 20)。每组测试数据的第一行是四个整数N,X,Y,MAX,用空格分隔。N 是平台的数目(不包括地面),X 和Y 是Jimmy 开始下落的位置的横竖坐标,MAX 是一次下落的最大高度。接下来的N
行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。1<=
N <= 1000,-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i =
1…N)。所有坐标的单位都是米。 Jimmy 的大小和平台的厚度均忽略不计。如果Jimmy 恰好落在某个平台的边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保Jimmy 一定能安全到达地面。 输出要求
对输入的每组测试数据,输出一个整数,Jimmy 到地面时可能的最早时间。
输入样例 1
3 8 17 20
0 10 8
0 10 13
4 14 3
输出样例 23

将题目所给条件加以转化,即可得到 一个标准的动态规划问题:

#include<iostream>
#include<vector>
#include<algorithm>
#include<memory.h>
#include<stdio.h>
using namespace std;
#define INF 100000
int N, max1;
struct island
{
	int leftx, rightx, h;
};

bool cmp1(island a, island b) {
	return a.h < b.h;
}

island island_[1010];
int leftmin[1010];
int rightmin[1010];

int mintime(int L, bool isleft) {
	int y = island_[L].h, i, x;
	if (isleft) x = island_[L].leftx;
	else x = island_[L].rightx;
	for (i = L + 1; i <= N; i++) {
		if (island_[i].leftx=<x && island_[i].rightx>=x) break;
	}
	if (i <= N) {
		if (y - island_[i].h > max1) return INF;
	}
	else {
		if (y > max1) return INF;
		else return y;
	}
	int lefttime = y - island_[i].h + x - island_[i].leftx;
	int righttime = y - island_[i].h + island_[i].rightx - x;
	if (leftmin[i] == -1) leftmin[i]=mintime(i, true);
	if (rightmin[i] == -1)rightmin[i] = mintime(i, false);
	lefttime += leftmin[i];
	righttime += rightmin[i];
	if (lefttime < righttime) {
		return lefttime;
	}
	else {
		return righttime;
	}
}

由于输入乱序。先定义cmp函数供按照高度排序使用;产生最小时间的函数包括两个参量:浮岛编号与用于判别左右的布尔值;找到下一个浮岛后,优先排除特殊情况;最后进行动态规划处理。

4、

我们称序列Z = < z1, z2, …, zk >是序列X = < x1, x2, …, xm >的子序列当且仅当存在严格上升的序列< i1, i2, …, ik >,使得对j = 1, 2, … ,k, 有xij = zj。比如Z = < a, b, f, c > 是X = < a, b, c, f, b, c >的子序列。 现在给出两个序列X
和Y,你的任务是找到X 和Y 的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z 既是X 的子序列也是Y 的子序列。 输入数据
输入包括多组测试数据。每组数据包括一行,给出两个长度不超过200 的字符串,表示两个序列。两个字符串之间由若干个空格隔开。 输出要求
对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度。
输入样例 abcfbc abfcab
programming contest
abcd mnp
输出样例
4
2
0

运用递推求解,要知道字符串1的第i位与字符串2的第j位之前公共子序列的最大长度,只需分两种情况讨论,当串1第i位与串2第j相等时,只需将串1第i-1位与串2第j-1位的最长长度+1,否则则取串1第i位与串2第j-1位、串1第i-1位与串2第j位最长长度的最大值;

#include<cstdio>
#include<string.h>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 210;
char s1[maxn], s2[maxn];
int sta[maxn][maxn];
int main() {
	int a, b;
	while (scanf("%s%s", s1+1, s2+1)>0) {
		int len1 = strlen(s1+1);
		int len2 = strlen(s2+1);
		fill(sta[0], sta[0] + (len1+1) * (len2+1), 0);
		for(int i=1;i<=len1;i++)
			for (int j = 1; j <= len2; j++) {
				if (s1[i] == s2[j]) {
					sta[i][j] = sta[i - 1][j - 1]+1;
				}
				else{
					a = sta[i - 1][j];
					b = sta[i][j - 1];
					sta[i][j] = max(a, b);
				}
			}
		printf("%d", sta[len1][len2]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44705116/article/details/102570787
今日推荐