题目:两种水果杂交出一种新水果,现在给新水果取名,要求这个名字中包含了以前两种水果名字的字母,并且这个名字要尽量短。也就是说以前的一种水果名字arr1是新水果名字arr的子序列,另一种水果名字arr2也是新水果名字arr的子序列。设计一个算法求arr。
算法分析:
- 根据两个字符数组arr1和arr2建立动态规划dp数组,取得最大重叠子串的个数;
- 由最大重叠子串可知,重叠部分在父串中出现个数为1,设置b数组记录当前状态下,字符是否为重复字符。当重复字符全部打印完后,其他字符按照顺序直接打印;
- 如果arr1[i]和arr2[j]是相等的,那么打印其中一个即可,用s[i][j]=1记录这种情况;
- 如果arr1[i]和arr2[j]是相等的,且dp[i-1][j]>dp[i][j-1],那么是s[i][j]=2;其余为s[i][j]=3;
- 打印的时候按照这三种情况,选择回退方向;
本题如果使用map,很容易通过遍历得到结果,但由于是学时动态规划,所以使用动态规划的求解方法,首先得到最长公共子序列的长度的数组,根据数组长度或得打印策略。
使用map容器很容易得到,但是有个问题,它是按键的大小默认排序的;
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
char x[1005],y[1005];
int main(){
string s1,s2;
cin>>s1>>s2;
strcpy(x,s1.c_str());
strcpy(y,s2.c_str());
int m = s1.size();
int n = s2.size();
map<char,int> m1;
for(int i = 0; i<m; i++){
m1[x[i]]++;
}
for(int i = 0; i<n; i++){
m1[y[i]]++;
}
for(map<char,int>::iterator it = m1.begin();it!=m1.end();it++){
cout<<it->first;
}
}
使用动态规划
#include <iostream>
#include <cstring>
using namespace std;
const int N = 105;
//子序列
char arr1[N];
char arr2[N];
//动态规划数组
int c[N][N];
int s[N][N];
int m,n;
/*apple peach*/
int solve(char*x,char*y){
for(int i=1; i<=m;i++) s[i][0] = 3;
for(int i=1; i<=n;i++) s[0][i] = 3;
for (int i=1; i<=m; i++){ //逐行向下
for (int j=1; j<=n; j++){ //从左至右扫描求值
if (arr1[i-1]==arr2[j-1])
{ c[i][j]=c[i-1][j-1]+1;
s[i][j]=1; }
//由 c[i-1][j-1]计算 c[i][j] }
else if(c[i-1][j]>=c[i][j-1]){
c[i][j]=c[i-1][j];
s[i][j]=2;
}else{
c[i][j]=c[i][j-1];
s[i][j]=3;
}
}
}
return c[m][n]; //返回最优解值
}
void CLCS(int i,int j){
//构造最长公共子序列并输出
if (i==0 && j==0) return; //终止条件
if (i==0){
CLCS(i,j-1);
cout<<arr2[j-1];
return;
}else if(j==0){
CLCS(i-1,j);
cout<<arr1[i-1];
return;
}
if (s[i][j]==1){
CLCS(i-1,j-1);
cout<<arr1[i-1];
return;//输出
}
else if (s[i][j]==2){
CLCS(i-1,j);
cout<<arr1[i-1];
return;
}
else {
CLCS(i,j-1);
cout<<arr2[j-1];
return;
}
}
int main() {
while(true){
//初始化
memset(c,0,sizeof(c));
memset(s,0,sizeof(s));
string s1,s2;
cout<<"输入的字符串为:" <<endl;
cin>>s1>>s2;
//将字符串转换为字符数组
m = s1.size();
n = s2.size();
strcpy(arr1,s1.c_str());
strcpy(arr2,s2.c_str());
solve(arr1,arr2);
//输出dp数组
for(int i = 0;i<=m;i++){
for(int j = 0; j<=n;j++)
{
cout<<c[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
//输出s数组
for(int i = 0;i<=m;i++){
for(int j = 0; j<=n;j++)
{
cout<<s[i][j]<<" ";
}
cout<<endl;
}
cout<<endl;
cout<<"杂交水果为:";
CLCS(m,n);
cout<<endl;
}
return 0;
}
结果如下: