最长公共子序列(LCS)
- dp[i][j] = x表示第一个字符串前i个位置和第二个字符串前j个位置的最长公共子序列长度为x
- if(s1[i]==s2[j]) dp[i][j]= dp[i-1][j-1]+1;
- else dp[i][j] = max(dp[i-1][j],dp[i][j-1])
POJ1458(裸题)
代码:很好理解。因为字符串从0开始,所以我i和j都分别加1记录。
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int const N = 1000 + 10;
int dp[N][N]; //dp[i][j]表示第一个字符串前i个位置和第二个字符串前j个位置的最长公共子序列长度为x
string s1,s2;
int main(){
while(cin>>s1>>s2){
memset(dp,0,sizeof(dp));
for(int i=0;i<s1.length();i++)
for(int j=0;j<s2.length();j++)
if(s1[i] == s2[j]) dp[i+1][j+1] = dp[i][j] + 1; //如果相同,那么
else dp[i+1][j+1] = max(dp[i][j+1],dp[i+1][j]);
printf("%d\n",dp[s1.length()][s2.length()]);
}
}
UVA11584
题解:
- dp[i]表示0到i回问串的个数
- p[i][j]表示i到j是否为回文串
- 所以dp[i] = min(dp[i],dp[j-1] + p[j][i] == true ? 1 : 0)
#include <bits/stdc++.h>
using namespace std;
int const N = 1000 + 10;
int const inf = 0x7f7f7f7f;
char s[N];
int n,dp[N],p[N][N];
bool ok(char *s,int i,int j){
while(i < j){
if(s[i] != s[j]) return false;
++i,--j;
}
return true;
}
int solve(char *s){
int len = strlen(s);
dp[0] = 1;
for(int i=1;i<len;i++){
dp[i] = dp[i-1] + 1;
for(int j=0;j<i;j++)
if(ok(s,j,i)) dp[i] = min(dp[i],dp[j-1]+1);
}
return dp[len-1];
}
int main(){
scanf("%d",&n);
while(n--){
scanf(" %s",s);
printf("%d\n",solve(s));
}
return 0;
}