个人最近做的动态规划大型总结!!!

首先大多数题的套路(搬运至大佬,见水印)

 

 

 

最长回文子序列:字符串反转+动态规划,最长公共子序列LCS算法

题目思想大概是这样:cabbeaf:回文子序列有:c,a,aa,bb,,aba,abba,e,f,最长的就是abba,所以输出长度为4

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N = 2000;
int dp[N][N];
int main()          //颠倒字符串顺序 ,正序、倒序比较 从而求出最长子序列
{
	int i,j;
	string str,a;
	cin >> str;
	a = str;
	reverse(a.begin(),a.end());
	int lena;
	lena = str.length();
	for (i = 1; i <= lena; i++)
	for (j = 1; j <= lena; j++)
	{
		if(str[i - 1] == a[j - 1])
		dp[i][j] = dp[i - 1][j - 1] + 1; //从第一层开始建立数组堆 
		else
		dp[i][j] = max(dp[i-1][j],dp[i][j-1]);// 读大的一个 也是建立 
	}

    cout << dp[lena][lena]; //即为最长公共子序列
	/*cout << lena - dp[lena][lena]; */   根据规律可知由 字符串长度 减去 最长公共子序列 
	return 0;
}

  一个字符串,如果从左到右读和从右到左读是完全一样的,比如"aba",我们称其为回文串。现在给你一个字符串,可在任意位置添加字符,求最少添加几个字符,才能使其变成一个回文串。 

上方 /* */为这一问解答

 

大概图解思想

 

 


题目二

#include<iostream>
#include<algorithm>
using namespace std;

const int N = 2000;
int dp[N][N];
int a[N][N];

int main()
{
	int i,n,j;
	cin >> n;
	for (i = n - 1; i >= 1; i--)  //  建立二维数组  舍弃了 第0行第0列方便思考!!
	for (j = 1; j <= i; j++)
	cin >> a[i][j];
	for (j = 1; j <= n - 1; j++)  // 将一个新的数组(用来保存每一层相加后的结果的数组)中输入a[i][j]的第一行
	dp[n-1][j] = a[n-1][j];
	
	for (i = n - 2; i >= 1; i--)
	for (j = 1; j <= i; j++)
	dp[i][j] = min(dp[i+1][j]+a[i][j],dp[i+1][j+1]); //最巧妙的地方 数组由下到上建立,注意是从 下往上建立
	cout <<dp[1][1];//最后 1 的 1就是最大值
	 
}

好像还有点问题 ,pta的有一个测试点过不了,但不知道问题出在哪 先保存着再说。。。。。

https://zhuanlan.zhihu.com/p/32301695?utm_source=qq&utm_medium=social&utm_oi=931458456091721728  具体思想思路


#include <stdio.h>
#define MAX 101
int map[MAX][MAX];
int S[MAX][MAX];
int F[MAX][MAX];
 
int m, n;
int max(int a, int b)
{
	return a > b ? a : b;
}
int dp(int i, int j) // 倒推,用递归的方法从大的号码 往小号 累加 最后[0][0]就是最大值 
{
	if (i < 0 || j < 0)	return -10000;
	if (F[i][j])	return F[i][j]; // F[i][j]存放的就是从右下角到达该点捡起宝物价值最大值,最后F[0][0]即为所求
	if (i == m && j == n)//ij条件交集放前面 
	{
		return F[i][j] = map[i][j];
	}
	 if (i == m) // 到达底端,就只能往右走
	{
		return F[i][j] = map[i][j] + dp(i, j + 1);//注意dp是递归不是数组
	}
	 if (j == n) // 到达右端,只能往下走
	{
		return F[i][j] = map[i][j] + dp(i + 1, j);
	}
	else // 否则在这一点能够获得的最大价值就是该点的宝物价值加上往右或者往下走能够获得的最大价值
	{
		return F[i][j] = map[i][j] + max(dp(i + 1, j), dp(i, j + 1));
	}
}
 
int s(int i, int j)
{
	if (i < 0 || j < 0)	return -10000;
	if (S[i][j])	return S[i][j];
	if (i == m || j == n)//到边界,只能往右或者往下,只有唯一路径,不用继续走了 
	{
		return S[i][j] = 1;
	}
	else
	{
		if (F[i][j] == map[i][j] + F[i][j + 1])	S[i][j] += s(i, j + 1);// 调用递归(自己一开始想不到的地方)
		if (F[i][j] == map[i][j] + F[i + 1][j])	S[i][j] += s(i + 1, j);
		return S[i][j];
	}
}
 
int main()
{
	int i, j;
	scanf("%d %d", &m, &n);
	for (i = 1; i <= m; ++i)
	{
		for (j = 1; j <= n; ++j)
		{
			scanf("%d", &map[i][j]);
		}
	}
	printf("%d ", dp(1, 1));
	printf("%d\n",s(1,1));
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值