(UESTC

来源:互联网 发布:c语言数组存储方式 编辑:程序博客网 时间:2024/06/06 06:45

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;}
原创粉丝点击