最长公共子序列长度(LCS)
问题描述:求两个字符串的最长公共子序列长度。(子序列不一定是连续的)
分析:设二维数组dp(i, j)是字符str1[i]与str2[j]之前的LCS。给出两个字符串str1和str2,现在假设判断str1[i]和str2[j]两个字符,这样可以分为两种情况:
1.两者相同
2.两者不同
代码:
#include<bits/stdc++.h>
using namespace std;
const int M = 110;
int dp[M][M];
int main()
{
string str1, str2;
cin >> str1 >> str2;
memset(dp, 0, sizeof dp);
for(int i = 0; i < str1.size(); i++)
{
for(int j = 0; j < str2.size(); j++)
{
if(str1[i] == str2[j])
dp[i + 1][j + 1] = dp[i][j] + 1;
else
dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);
}
}
cout << dp[str1.size()][str2.size()];
return 0;
}
单调递增最长子序列
问题描述:设计一个O(n^2)时间的算法,找出由n个数组成的序列的最长单调递增子序列的长度。
分析:开一个一维数组dp。令dp[i]为以v[i]结尾的最大递增子序列。那么当v[i]大于v[j]时有以下状态转移方程:
代码:
#include<iostream>
using namespace std;
const int M = 1100;
int n, v[M], dp[M];
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> v[i];
for(int i = 0; i < n; i++)
{
dp[i] = 1;
for(int j = 0; j < i; j++)
{
if(v[j] < v[i])
dp[i] = max(dp[i], dp[j] + 1);
}
}
cout << dp[n - 1];
return 0;
}
最长有序子序列
问题:基本同上
分析:只要对于dp数组进行排序即可。不过在交时要注意格式。
代码:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int M = 1100;
int v[M], t, n;
void slove()
{
cin >> n;
vector<int> dp(n, 1);
for(int i = 0; i < n; i++)
cin >> v[i];
for(int i = 0; i < n; i++)
{
for(int j = 0; j < i; j++)
{
if(v[j] < v[i])
dp[i] = max(dp[i], dp[j] + 1);
}
}
sort(dp.begin(), dp.end());
cout << dp[dp.size() - 1] ;
return ;
}
int main()
{
cin >> t;
while(t--)
{
if(t == 0)
slove();
else
{
slove();
cout << endl;
cout << endl;
}
}
return 0;
}
最大连续子序列
问题描述:给定K个整数的序列{ n(1),n(2),…,n(K) },其任意连续子序列可表示为{ n(i),n(i+1),…,n(j)},其中 1≤i≤j≤K。最大连续子序列是所有连续子序列中元素和最大的一个。例如,给定序列{ -2,11,-4,13,-5,-2 },其最大连续子序列为{ 11,-4,13 },最大和为20。 要求编写程序得到最大和,并输出子序列的第一个元素和最后一个元素。
分析:求出前缀和,j从后往前遍历,i从j往前遍历即可。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int M = 1e4 + 5;
const int INF = 0x3f3f3f3f;
int t, n, v[M], sum[M];
void slove(int n)
{
int flag = 0;
for(int i = 1; i <= n; i++)
{
cin >> v[i];
if(v[i] > 0)
flag = 1;
sum[i] = sum[i -1] + v[i];
}
if(!flag)
{
cout << 0 << " " << v[1] << " " << v[n] << endl;
return ;
}
int l = 0, r = 0, index_l = 0, index_r = 0;
int max_n = 0 - INF;
for(int j = n; j > 0; j--)
{
for(int i = j - 1; i >= 0; i--)
{
if(max_n <= sum[j] - sum[i])
{
max_n = sum[j] - sum[i];
l = v[i + 1], r = v[j];
}
}
}
cout << max_n << " " << l << " " << r << endl;
return ;
}
int main()
{
cin >> t;
while(t != 0)
{
slove(t);
cin >> t;
}
return 0;
}