(UESTC - 1006)最长上升子序列(DP,输出子序列的元素)

Time limit1000 ms Memory limit65535 kB
一个数的序列B=(b1,b2,⋯,bS)B=(b1,b2,⋯,bS),当b1<b2<⋯<bSb1<b2<⋯<bS 的时候,我们称这个序列是上升的。对于给定的一个序列A=(a1,a2,⋯,aN)A=(a1,a2,⋯,aN),我们可以得到一些上升的子序列(ai1,ai2,⋯,aiK)(ai1,ai2,⋯,aiK),这里1≤i1<i2<⋯<iK≤N1≤i1<i2<⋯<iK≤N。比如,对于序列(1,7,3,5,9,4,8)(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7)(1,7), (3,4,8)(3,4,8)等等。这些子序列中最长的长度是44,比如子序列(1,3,5,8)(1,3,5,8)。

你的任务,就是对于给定的序列,求出最长最小的上升子序列。所谓最长最小的子序列,是指若有多个最长子序列时,存在一个子序列A=(as1,as2,⋯,ask)A=(as1,as2,⋯,ask),对其它任意最长子序列B=(at1,at2,⋯,atk)B=(at1,at2,⋯,atk),有前i−1i−1个元素相等, 而asi<atiasi<ati,则AA是最长最小的上升子序列。

Input
有多组测试数据。输入的第一行是整数TT(0<T≤1000<T≤100),表示测试数据的组数。每组测试数据占一行,第一个数是序列的长度NN (1≤N≤10001≤N≤1000)。紧随其后是序列中的NN 个整数,该行每个数后均有一个空格,这些整数的取值范围都在00 到1000010000。该行没有其它多余的符号。

Output
对应每组输入,先输出最长最小的上升子序列长度,再输出最长最小的上升子序列,占一行。每个数后应有一个空格,该行不能有其它多余的符号。

Sample Input
1
7 1 7 3 5 9 4 8
Sample Output
4 1 3 4 8

分析:这道题比之前写的最长上升子序列多了输出部分,就用了一个数组实现的链表来记录下标
设dp[i]为第i个数到第n个数的最长上升子序列的长度

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<string>
#include<set>
#include<vector>
#include<iostream>
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]<dp[j]+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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值