【计算机专业复试机试】十三:常见动态规划问题



十三、常见动态规划问题

13.1 从分治法到动态规划

在这里插入图片描述

动态规划:
1、设计一个数据结构,记录不同规模问题的答案
2、数据结构采用从小到大的方式去生成
一般流程:
1、大问题分解 -> 小问题
2、解决最小问题
3、记录最小问题,从最小问题出发回推大问题

跳台阶
在这里插入图片描述

先用分治法去思考问题(从大问题到小问题),再反向思考
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

using namespace std;

int main() {
	int n;
	scanf("%d", &n);
	int dp[16] = { 0 };
	dp[1] = 1;
	dp[2] = 2;
	for (int i = 3; i <= n; i++) {
		dp[i] = dp[i - 1] + dp[i - 2];
	}
	printf("%d\n", dp[n]);
	return 0;
}

13.2 放苹果

动态规划和排列组合问题

二维数组
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string>
using namespace std;

int main() {
	int dp[13][13] = { 0 };
	int n, m;	//dp[m][n] 将n个苹果放入m个盘子中
	while (scanf("%d%d", &m, &n) != EOF) {
		memset(dp, 0, 13 * 13);
		for (int i = 0; i <= m; i++) {
			dp[i][1] = 1;
		}
		for (int j = 1; j <= n; j++) {
			dp[0][j] = 1;
			dp[1][j] = 1;
		}
		for (int i = 2; i <= m; i++) {
			for (int j = 2; j <= n; j++) {
				if (j > i) {
					dp[i][j] = dp[i][i];
				}
				else {
					dp[i][j] = dp[i][j - 1] + dp[i - j][j];
				}
			}
		}
		printf("%d\n", dp[m][n]);
	}

}

13.3 最长公共子序列

和线性数据结构相关的动态规划问题

两个序列 求最长公共子序列 最长公共连续子序列
一个序列内 求最大子序列和

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string>
#include<algorithm>
using namespace std;

int dp[1001][1001]; //dp[i][j] s1的前i个元素 s2的前j个元素的最大公共长度

int main() {
	int m, n;
	char s1[1001], s2[1001];
	scanf("%d%d", &n, &m);
	scanf("%s%s", s1, s2);
	memset(dp, 0, 1002 * 1002);
	for (int i = 0; i <= n; i++) {
		dp[i][0] = 0;
	}
	for (int j = 0; j <= m; j++) {
		dp[0][j] = 0;
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= m; j++) {
			if (s1[i-1] == s2[j-1]) {
				dp[i][j] = dp[i - 1][j - 1] + 1;
			}
			else {
				dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
			}
		}
	}
	printf("%d\n", dp[n][m]);
	return 0;
}

13.4 最长公共子串

在这里插入图片描述在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string>
#include<algorithm>

using namespace std;
short dp[10001][10001] = { 0 };
int main() {
	int n, m;
	char s1[10001];
	char s2[10001];
	scanf("%s%s", s1, s2);
	n = strlen(s1);
	m = strlen(s2);
	short curmax = 0;
	for (int i = 0; i <= n; i++) {
		dp[i][0] = 0;
	}
	for (int j = 0; j <= m; j++) {
		dp[0][j] = 0;
	}
	for (int i = 0; i <= n; i++) {
		for (int j = 0; j <= m; j++) {
			if (s1[i-1] >= 'a' && s1[i-1] <= 'z' && s1[i-1] == s2[j-1]) {
				dp[i][j] = dp[i - 1][j - 1] + 1;
				curmax = max(dp[i][j], curmax);
			}
			else {
				dp[i][j] = 0;
			}
		}
	}
	printf("%d\n", curmax);
	return 0;
}

13.5 最大序列和

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<algorithm>
#include<vector>
#include<string>
long long s[1000001];	//-10^9 -10^9 
long long dp[1000002]; //dp[i]前i个元素 必须包含右边缘的最大子序列和
using namespace std;

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%lld", &s[i]);
	}
	dp[1] = s[0];
	long long curmax = dp[1];
	for (int i = 2; i <= n; i++) {
		if (dp[i - 1] < 0) {
			dp[i] = s[i - 1];
		}
		else {
			dp[i] = s[i - 1] + dp[i - 1];
		}
		curmax = max(curmax, dp[i]);
	}
	printf("%lld\n", curmax);
	return 0;
}

13.6 背包问题

在这里插入图片描述
在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<algorithm>

using namespace std;


int main(){
	int c,n;
	scanf("%d%d",&c,&n);
	int p[101] = {0};
	int v[101] = {0}; 	
	for(int i = 0; i< n;i++){
		scanf("%d%d",&p[i],&v[i]);
	}
	int dp[1001][101];
	//dp[x][y] 在总额度不超过x的情况,考察0-y-1号商品的最大评分
	for(int x=0;x<=c;x++){
		dp[x][0] = 0;
	}
	for(int y=0; y<=n;y++){
		dp[0][y] = 0;
	}
	for(int x=1;x<=c;x++){
		for(int y=1;y<=n;y++){
			if(x-p[y-1]<0){
				dp[x][y] = dp[x][y-1];
			}else{
				dp[x][y] = max(dp[x][y-1],dp[x-p[y-1]][y-1]+v[y-1]);
			}
		}
	}
	printf("%d\n",dp[c][n]);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一叶怎知秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值