首先大多数题的套路(搬运至大佬,见水印)
最长回文子序列:字符串反转+动态规划,最长公共子序列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;
}