动态规划类题目解题步骤:
1、定义数组元素的含义
2、找出数组元素之间的关系式
3、找出初始值
1.最大序列和
给出一个整数序列S,其中有N个数,定义其中一个非空连续子序列T中所有数的和为T的“序列和”。 对于S的所有非空连续子序列T,求最大的序列和。 变量条件:N为正整数,N≤1000000,结果序列和在范围(-2^63,2^63-1)以内。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
while(cin>>n){
int pos = 0;
long long dp[n];
long long num;
int len = n;
while(n--){
cin>>num;
dp[pos] = num;
pos++;
}
for(int i=1;i<len;i++){
dp[i]=max(dp[i-1]+dp[i],dp[i]);
}
long long res = *max_element(dp, dp+len);
printf("%lld\n",res);
}
}
2.最长连续公共子序列
输入两个字符串s1,s2。输出最长连续公共子串长度和最长连续公共子串。
#include<bits/stdc++.h>
using namespace std;
int dp[101][101];
int main(){
string s1,s2;
while(cin>>s1>>s2){
int len1 = s1.size();
int len2 = s2.size();
for(int i=0;i<=len1;i++){
dp[i][0] = 0;
}
for(int j=0;j<=len2;j++){
dp[0][j] = 0;
}
int max_len = 0;
int ri;
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(s1[i-1]==s2[j-1]){
dp[i][j] = dp[i-1][j-1]+1;
if(dp[i][j]>=max_len){
max_len=dp[i][j];
ri = i;
}
}else{
dp[i][j] = 0;
}
}
}
cout<<max_len<<endl;
string s = s1.substr(ri-max_len,max_len);
cout<<s<<endl;
}
}
3.最长公共子序列
输入两个字符串s1,s2。输出最长连续公共子串长度和最长连续公共子串。
与上题只有两个区别,其一是s1[i-1]不等于s2[j-1]后的处理,其二是此时dp数组的最大值一定出现在dp[len1][len2],不需要再判断和记录。
#include<bits/stdc++.h>
using namespace std;
int dp[1001][1001];
int main(){
string s1,s2;
while(cin>>s1>>s2){
int len1 = s1.size();
int len2 = s2.size();
for(int i=0;i<=len1;i++){
dp[i][0] = 0;
}
for(int j=0;j<=len2;j++){
dp[0][j] = 0;
}
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;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]);
}
}
}
cout<<dp[len1][len2]<<endl;
}
}
4.字符串编辑距离
易错点:每次求dp[i][j]比较的是s1[i-1]和s2[j-1],因为dp数组的i/j与字符串的i/j含义不同,前者是指长度,后者是指第i位字符,长度为i的字符串的字符序号是i-1,因为是从0开始标号。
#include<bits/stdc++.h>
using namespace std;
int dp[1001][1001]={0}; //长度为i的s1,转化为长度为j的s2,共需要多少步
int main(){
string s1,s2;
cin>>s1>>s2;
int len1 = s1.size();
int len2 = s2.size();
// i=0时,只能对s1进行插入操作
for(int j = 1;j<=len2;j++){
dp[0][j] = dp[0][j-1] + 1;
}
// j=0时,只能对s2进行删除操作
for(int i = 1;i<=len1;i++){
dp[i][0] = dp[i-1][0] + 1;
}
for(int i = 1;i<=len1;i++){
for(int j = 1;j<=len2;j++){
if(s1[i-1]==s2[j-1]){
dp[i][j] = dp[i-1][j-1];
}else{
dp[i][j] = min(min(dp[i-1][j-1],dp[i][j-1]),dp[i-1][j])+1;
}
}
}
cout<<dp[len1][len2];
}