Time limit1000 ms Memory limit65535 kB
一个数的序列B=(b1,b2,⋯,bS)B=(b1,b2,⋯,bS),当b1
1≤i1
你的任务,就是对于给定的序列,求出最长最小的上升子序列。所谓最长最小的子序列,是指若有多个最长子序列时,存在一个子序列A=(as1,as2,⋯,ask)A=(as1,as2,⋯,ask),对其它任意最长子序列B=(at1,at2,⋯,atk)B=(at1,at2,⋯,atk),有前i−1i−1个元素相等, 而asi
Input
有多组测试数据。输入的第一行是整数TT(0
Output
对应每组输入,先输出最长最小的上升子序列长度,再输出最长最小的上升子序列,占一行。每个数后应有一个空格,该行不能有其它多余的符号。
Sample Input
1
7 1 7 3 5 9 4 8
Sample Output
4 1 3 4 8
分析:这道题比之前写的最长上升子序列多了输出部分,就用了一个数组实现的链表来记录下标
设dp[i]为第i个数到第n个数的最长上升子序列的长度
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
#define mem(a) memset(a,0,sizeof(a))
const int N=1e3+5;
int dp[N],ne[N],a[N];///ne为链表数组
int n;
void solve()
{
mem(dp);///初始化
mem(ne);//初始化
for(int i=n; i>=0; i--)
{
for(int j=i+1; j<=n; j++)
if(a[j]>a[i])
{
if(dp[i]1||(dp[i]==dp[j]+1&&a[ne[i]]>a[j]))///上升子序列长度小或者长度相等时上升序列的数不是最小
{
dp[i]=dp[j]+1;
ne[i]=j;
//printf("%d %d %d %d\n",i,dp[i],ne[i],a[ne[i]]);
}
}
}
//printf("%d %d %d\n",dp[0],ne[0],a[ne[0]]);
printf("%d ",dp[0]);
for(int i=ne[0]; i!=0; i=ne[i])///沿着链表输出直到ne[i]不为0
{
//printf("%d %d\n",i,ne[i]);
printf("%d ",a[i]);
}
printf("\n");
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
solve();
}
return 0;
}