最长公共子序列
一个给定序列的子序列是在该序列中删去若干元 素后得到的序列。
问题描述 :Common Subsequence (HDU - 1159)
给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。最长公共子序列:公共子序列中长度最长的子序列。最长公共子序列问题:给定两个序列X和Y,找出X和Y的一个最长公共子序列。
解题方法
1.蛮力法
程序代码:
#include<bits/stdc++.h>
using namespace std;
//判断z是不是y的子序列
bool judge(string z,string y){
//遍历字符串y
for(int i=0,j=0;i<y.length();i++) {
if(y[i]==z[j])
j++;
if(j == z.length())
return true;
}
return false;
}
int main(){
string x,y;
while(cin>>x>>y){
int ans=0; //最长公共子序列长度为0
if(y.length()<x.length())
swap(x,y);
//枚举x的所有子序列,二进制枚举
int n=x.length();
for(int i=0;i<(1<<n);i++){
// 通过枚举方案i得到子序列z
string z;
for(int j=0;j<n;j++){
//i的二进制的1对应的元素取出来
if(i & (1<<j))
z += x[j];
}
//判断z是不是y的子序列
if(judge(z,y)) {
int t=z.length();
ans=max(ans,t);
}
}
cout<<ans<<endl;
}
return 0;
}
2.二进制法求子集
程序代码:
#include <bits/stdc++.h>
using namespace std;
void print_subset(int n){
for(int i=0; i< (1<<n); i++) {
//i:0~2n,每个i的二进制数对应一个子集。
for(int j=0;j<n;j++) //打印一个子集,即
打印i的二进制数中所有的1。
if(i & (1<<j))
cout<< j << " ";
cout << endl;
}
}
int main(){
int n;
cin>>n; // n:集合中元素的总数量。
print_subset(n); // 打印所有的子集。
}
3.动态规划
解题思路:
程序代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1000+10;
int dp[N][N];
//int f(string x,string y){
// int n=x.length();
// int m=y.length();
// if(n==0 || m==0)
// return 0;
// //尾字符相同
// if(x[n-1]==y[m-1])
// return f(x.erase(x.length()-1,1),y.erase(y.length()-1,1))+1;
// //不同求最优解
// return max(f(x.erase(x.length()-1,1),y),f(x,y.erase(y.length()-1,1)));
//}
int main(){
string x,y;
cin>>x>>y;
int n=x.length();
int m=y.length();
x.insert(0,"#");
y.insert(0,"#");
memset(dp,0,sizeof(dp));
//依次填表
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
//相等
if(x[i] == y[j])
dp[i][j]=dp[i-1][j-1]+1;
//不相等
else{
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}