题意:求两个数列的最长公共上升子序列.输出长度和任意一种方案.
这道题我真的做到崩溃,搞了几个小时,原本在洛咕上的方法在POJ上全WA了.个人认为是输出方案的问题.
分析:设\(f[i][j]\)表示\(A\)序列前i个和\(B\)序列前j个构成的最长公共上升子序列的长度.
\(A[i]\)不等于\(B[j]\)时,\(f[i][j]=f[i-1][j]\)
\(A[i]=B[j]\)时,\(f[i][j]=max(f[i][j],f[i-1][t]+1)\),t为最长公共上升子序列结尾的元素的位置.
因为要输出方案,所以在每次更新序列时,再开一个数组记录一下,最后递归输出方案.
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
const int N=505;
int a[N],b[N],f[N][N],g[N][N];
inline void print(int n,int pos){
if(!pos)return;
print(n,g[n][pos]);
printf("%d ",b[pos]);
}
int main(){
int n=read();for(int i=1;i<=n;i++)a[i]=read();
int m=read();for(int i=1;i<=m;i++)b[i]=read();
for(int i=1,t=0;i<=n;i++,t=0)
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];g[i][j]=g[i-1][j];
if(a[i]==b[j]&&f[i-1][t]+1>f[i][j]){
f[i][j]=f[i-1][t]+1;
g[i][j]=t;
}
if(a[i]>b[j]&&f[i-1][t]<f[i-1][j])t=j;
}
int pos=0;
for(int i=1;i<=m;i++)if(f[n][i]>f[n][pos])pos=i;
printf("%d\n",f[n][pos]);
print(n,pos);puts("");
return 0;
}
因为\(f[i][j]\)都是由\(f[i-1][j]\)转移而来的,所以可以滚掉第一维数组,优化空间.
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
const int N=505;
int a[N],b[N],f[N],g[N];
inline void print(int pos){
if(!pos)return;
print(g[pos]);
printf("%d ",b[pos]);
}
int main(){
int n=read();for(int i=1;i<=n;i++)a[i]=read();
int m=read();for(int i=1;i<=m;i++)b[i]=read();
for(int i=1,t=0;i<=n;i++,t=0)
for(int j=1;j<=m;j++){
if(a[i]==b[j]&&f[t]+1>f[j]){
f[j]=f[t]+1;
g[j]=t;
}
if(a[i]>b[j]&&f[t]<f[j])t=j;
}
int pos=0;
for(int i=1;i<=m;i++)if(f[i]>f[pos])pos=i;
printf("%d\n",f[pos]);
print(pos);puts("");
return 0;
}
然后我又把递归输出方案改成了栈来实现,就在POJ上过了,真的好玄学啊.
//#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
using namespace std;
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
const int N=505;
int a[N],b[N],st[N],f[N][N],g[N][N];
int main(){
memset(g,-1,sizeof(g));
int n=read();for(int i=1;i<=n;i++)a[i]=read();
int m=read();for(int i=1;i<=m;i++)b[i]=read();
for(int i=1,t=0;i<=n;i++,t=0){
for(int j=1;j<=m;j++){
f[i][j]=f[i-1][j];
if(a[i]==b[j]&&f[i-1][t]+1>f[i][j]){
f[i][j]=f[i-1][t]+1;
g[i][j]=t;
}
if(a[i]>b[j]&&f[i-1][t]<f[i-1][j])t=j;
}
}
int pos=0;
for(int i=1;i<=m;i++)
if(f[n][i]>f[n][pos])pos=i;
printf("%d\n",f[n][pos]);
if(f[n][pos]<=0)return 0;
int tmp=pos;
for(int i=n;i>=1;i--)
if(g[i][tmp]!=-1)
st[++st[0]]=a[i],tmp=g[i][tmp];
for(int i=st[0];i>=2;i--)printf("%d ",st[i]);
printf("%d \n",st[1]);
return 0;
}