http://acm.hdu.edu.cn/showproblem.php?pid=1423
题意:求最长上升公共子序列。。。。
思路:动态规划咯,dp[i][k] 表示序列a中[1, i]和b序列中[1, k]选出的最长的以b[k]结尾的上升公共子序列,所以转移方程就是:
计算完后只要遍历一下dp[n][0]…dp[n][m],找出最大值就行了
代码如下:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n, m;
int arga[505];
int argb[505];
int dp[505][505];
int main()
{
int Test;
cin>>Test;
while(Test--){
cin>>n;
for(int i = 1; i <= n; i++){
cin>>arga[i];
}
cin>>m;
for(int i = 1; i <= m; i++){
cin>>argb[i];
}
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++)//遍历序列a
{
for(int k = 1; k <= m; k++) //遍历序列b
{
dp[i][k] = dp[i-1][k];
if(arga[i] == argb[k]){
int ans = 0;
for(int l = 0; l < k; l++){
if(arga[i] > argb[l] && dp[i-1][l] > ans) //找结尾比a[i]的最长上升公共子序列
ans = dp[i-1][l];
}
dp[i][k] = ans + 1; //等于最长的加一
}
}
}
int maxn = 0;
//找出最优的解
for(int i = 1; i <= m; i++){
if(dp[n][i] > maxn){
maxn = dp[n][i];
}
}
cout<<maxn<<endl;
if(Test)
cout<<endl;
}
return 0;
}
上面代码的复杂度是o(n^3), 解决这个题目是没有问题了,其实我们还可以优化,上面的for(int l = 0; l < k; l++)循环每次都只计算到 k-1 总是小于我们的上一个循环,所以我们可以这样改程序
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int n, m;
int arga[505];
int argb[505];
int dp[505][505];
int main()
{
int Test;
cin>>Test;
while(Test--){
cin>>n;
for(int i = 1; i <= n; i++){
cin>>arga[i];
}
cin>>m;
for(int i = 1; i <= m; i++){
cin>>argb[i];
}
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++){
int ans = 0;
for(int k = 1; k <= m; k++){
dp[i][k] = dp[i-1][k];
if(arga[i] > argb[k]) //因为当前所求的最长序列是以a[i]结尾的,所以我们可以这样。
ans = max(ans, dp[i-1][k]);
if(arga[i] == argb[k]){
dp[i][k] = ans + 1;
}
}
}
int maxn = 0;
for(int i = 1; i <= m; i++){
if(dp[n][i] > maxn){
maxn = dp[n][i];
}
}
cout<<maxn<<endl;
}
return 0;
}