动态规划
常见问题:
- 基础,斐波那契数列f(n)=f(n-1)+f(n-2)
- 背包问题
- 打家劫舍
- 股票问题
- 子序列问题
一篇讲的蛮清楚的文章:http://t.csdhttp://t.csdn.cn/mwjCWn.cn/mwjCW
DP数组的定义以及下标的含义
递推公式
DP数组如何初始化
DP数组遍历顺序
HJ52 计算字符的编辑距离
字符串A: abcdefg
字符串B: abcdef
通过增加或是删掉字符 ”g” 的方式达到目的。这两种方案都需要一次操作。把这个操作所需要的次数定义为两个字符串的距离。
要求:
给定任意两个字符串,写出一个算法计算它们的编辑距离。
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
int main() {
string str1, str2;
while (cin >> str1 >> str2) {
vector<vector<int>> dp(str1.size() + 1, vector<int>(str2.size() + 1, 0));
for (int i = 1; i <= str2.size(); i++) dp[0][i] = i;//str1从0个字符变成str2的i个字符需要i个插入操作
for (int i = 1; i <= str1.size(); i++) dp[i][0] = i;//str1从i个字符变成str2的0个字符也需要i个删除操作
for(int i=1;i<=str1.size();i++){
for (int j = 1; j <= str2.size(); j++) {
int op1 = dp[i-1][j] + 1;//删除字符str1[i-1]
int op2 = dp[i][j-1] + 1;//删除字符str2[j-1]
int op3 = dp[i-1][j-1];//替换操作
if(str1[i-1] != str2[j-1]){
op3++;
}
dp[i][j] = min(min(op1, op2), op3);//替换操作和删除操作取最小
}
}
cout << dp[str1.size()][str2.size()] << endl;
}
}
HJ61 放苹果
m个苹果放n个盘子,m<n的话,f(m,m),否则m苹果每个盘子都保证有苹果,和有空盘子的情况相加,进行递归。
在这里插入代码片#include<bits/stdc++.h>
using namespace std;
int sum=0;
int f(int m,int n){
if(m==0)return 1;
if(n==1)return 1;
if(m<n) return f(m,m);
return (f(m-n,n)+f(m,n-1));//放满盘子+不放满盘子
}
int main(){
int m,n;
cin>>m>>n;
sum=f(m,n);
cout<<sum;
return 0;
}
HJ75 公共字串计算
暴力枚举法
#include<bits/stdc++.h>
using namespace std;
int main(){
string a,b,temp;
cin>>a>>b;
if(a.length()>b.length()){
temp=a;
a=b;
b=temp;
}
int max=0;
for(int i=0;i<a.length();i++){
int len=0;
int k=i;
for(int j=0;j<b.length();j++){
//int l=j;
if(a[i]==b[j]){
len++;
i++;
}
else{
if(len>max) max=len;
j-=len;
len=0;
i=k;
}
}
if(len>max) max=len;
i=k;
}
cout<<max<<endl;
return 0;
}
动态规划方法
动态数组dp[i][j]表示在b中以第i个字符结尾,a中以第j个字符结尾时的公共子串长度。maxlen表示最长公共子串的长度。遍历一遍两个字符串:
如果b中第i和a中第j个字符相同,则在以i-1和j-1结尾的子串后面加上i、j一位仍然是子串,因此dp[i][j]=dp[i−1][j−1]+1。
!注意连续!否则不连续,置为0,如果b中第i和a中第j个字符不相同,则以他们结尾的子串不可能相同,dp[i][j]=0。
如果更新后的dp[i][j]比maxlen大,则更新最大子串信息。
#include <bits/stdc++.h>
using namespace std;
int LCS(const string& str1,const string& str2) {
// write code here
int m = str1.size();
int n = str2.size();
// dp[i][j] str1前i个字符和str2前j个字符(以其为尾字符)的最长公共子串长度
int dp[m+1][n+1];
int maxlen = 0;
//base case
for(int i = 0; i <= m; ++i) dp[i][0] = 0;
for(int j = 0; j <= n; ++j) dp[0][j] = 0;
for(int i = 1; i <= m; ++i) {
for(int j = 1; j <= n; ++j) {
if(str1[i-1] == str2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = 0;
if(dp[i][j] > maxlen) {
maxlen = dp[i][j];
}
}
}
return maxlen;
}
int main(){
string s1,s2;
cin>>s1>>s2;
cout<<LCS(s1,s2);
}