https://blog.csdn.net/someone_and_anyone/article/details/81044153
当串1 和 串2 的位置i和位置j匹配成功时,
dp[i][j]=dp[i-1][j-1]+1,也就是说此状态由状态dp[i-1][j-1]转移而来,用数组记录为1,
当匹配不成功时,dp[i-1][j]和dp[i][j-1]去一个最大的,用数组分别记为2和3.
根据记录数组寻找路径:
当记录数组为1时,说明次时的i和j想等,并且此状态由i-1和j-1转移而来,所以i=i-1,j=j-1
当记录数组为2时,说明此时i和j对应的数符不等,并且此状态由j-1转移而来,所以直接j--;
当记录数组为2时,说明此时i和j对应的数符不等,并且此状态由i-1转移而来,所以直接i--;
#include<bits/stdc++.h> using namespace std; const int N=1000+7; int dp[N][N]; int mark[N][N]; char s1[N],s2[N]; int main() { cin>>s1+1>>s2+1; int n=strlen(s1+1); int m=strlen(s2+1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ if(s1[i]==s2[j]){ dp[i][j]=dp[i-1][j-1]+1; mark[i][j]=1; } else if(dp[i][j-1]>dp[i-1][j]){ dp[i][j]=dp[i][j-1]; mark[i][j]=2; } else { dp[i][j]=dp[i-1][j]; mark[i][j]=3; } } string ans=""; int i=m,j=n; while(i>0&&j>0){ if(mark[i][j]==1) { ans+=s1[i]; i--;j--; } else if(mark[i][j]==2) { j--; } else i--; } reverse(ans.begin(),ans.end()); cout<<ans<<endl; return 0; }
LIS:最长上升子序列。
O(n^2):
定义dp[i]表示考虑到第i个元素,他可以拼接到从1~i-1中比它小的元素上去。
dp[i]=max(dp[k])+1,代码比较简单,在此省略。
O(nlogn):
定义dp[len]表示当长度为len时的最小元素。
code:
dp[1]=a[1];
int len=1;
for(int i=1;i<=n;i++){
if(a[i]>dp[len]) dp[++len]=a[i];
else *lower_bound(dp+1,dp+1+len,a[i])=a[i];
}
LCIS:最长公共上升子序列
定义状态dp[i][j]表示考虑前i个字符时,当选中第j个字符时的状态。
在这里第j个字符已经选了,所以前i个字符一定有和它匹配的,当第j个字符和第i个字符不匹配成功时,那第j个字符一定和
前i-1中的一个字符匹配喽,所以转移方程为dp[i][j]=dp[i-1][j],还是以j结尾。
当第j个字符和第i个字符匹配成功时,dp[i][j]=max(dp[i-1][k])+1,要在和前i-1个匹配的字符中选出状态最好的。
所以状态转移方程为:
dp[i][j]=dp[i-1][j],匹配成功。
dp[i][j]=max(dp[i-1][k])(k<=j)匹配不成功。
code:
void solve(int t){ ll n,m; cin >> n; for (ll i = 1; i <= n; i++) cin >> arr[i];; cin >> m; for (ll i = 1; i <= m; i++) cin >> brr[i]; ll mx = 0; for (ll i = 1; i <= n; i++) { mx = 0; for (ll j = 1; j <= m; j++) { dp[i][j] = dp[i - 1][j]; if (brr[j] < arr[i]) mx = max(mx, dp[i-1][j]); else if (arr[i] == brr[j]) dp[i][j] = mx + 1; } } ll ans = 0; for (ll i = 1; i <= m; i++) ans = max(ans, dp[n][i]); cout << ans<<"\n"<<"\n"; }
一个例题:
HDU1423:Greatest Common Increasing Subsequence
code:
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll N = 1E3 + 7;
ll arr[N];
ll brr[N];
ll dp[N][N];
void solve(int t){
ll n,m;
cin >> n;
for (ll i = 1; i <= n; i++) cin >> arr[i];;
cin >> m;
for (ll i = 1; i <= m; i++) cin >> brr[i];
ll mx = 0;
for (ll i = 1; i <= n; i++) {
mx = 0;
for (ll j = 1; j <= m; j++) {
dp[i][j] = dp[i - 1][j];
if (brr[j] < arr[i]) mx = max(mx, dp[i-1][j]);
else if (arr[i] == brr[j]) dp[i][j] = mx + 1;
}
}
ll ans = 0;
for (ll i = 1; i <= m; i++) ans = max(ans, dp[n][i]);
cout << ans<<"\n";
if(t) cout<<"\n";
}
int main(){
ll t;
cin >> t;
while (t--) solve(t);
return 0;
}