UESTC 1006 最长上升序列 脑洞+简单dp

来源:互联网 发布:申威26010 知乎 编辑:程序博客网 时间:2024/06/05 14:24
一个数的序列B=(b1,b2,,bS),当b1<b2<<bS 的时候,我们称这个序列是上升的。对于给定的一个序列A=(a1,a2,,aN),我们可以得到一些上升的子序列(ai1,ai2,,aiK),这里1i1<i2<<iKN。比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),(3,4,8)等等。这些子序列中最长的长度是4,比如子序列(1,3,5,8)

你的任务,就是对于给定的序列,求出最长最小的上升子序列。所谓最长最小的子序列,是指若有多个最长子序列时,存在一个子序列A=(as1,as2,,ask)

,对其它任意最长子序列B=(at1,at2,,atk),有前i1个元素相等, 而asi<ati,则A

是最长最小的上升子序列。

Input

有多组测试数据。输入的第一行是整数T

0<T100),表示测试数据的组数。每组测试数据占一行,第一个数是序列的长度N (1N1000)。紧随其后是序列中的N 个整数,该行每个数后均有一个空格,这些整数的取值范围都在010000

。该行没有其它多余的符号。

Output

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

Sample Input
17 1 7 3 5 9 4 8
Sample Output
4 1 3 4 8
乍一看,水题,但要求输出最小的,那我们可以这样处理:上升子序列,即要求后面的数大于前面的数。即这个数列中数所在的位置与值均大于前一个数。那么对于这题,我们可以先根据数值大小,对这一串数进行排序,保证后一个数大于等于前一个数,此时,我们对他们所在的位置求最长上升子序列。(这样,保证每次更新最长串长的时候,该序列都是最小的)
p.s. 此题的输出格式实在是坑。。。。。。
代码:
//By Sean Chen#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;struct node{    int pos,num;};int cmp(node a,node b){    return a.num<b.num;}int T,n;node a[1005];int pre[1005],dp[1005],rec[1005];int main(){    scanf("%d",&T);    while (T--)    {        scanf("%d",&n);        memset(pre,-1,sizeof(pre));        for (int i=0;i<n;i++)        {            scanf("%d",&a[i].num);            a[i].pos=i;        }        sort(a,a+n,cmp);        /*for (int i=0;i<n;i++)            cout<<a[i].num<<' ';        cout<<endl;        for (int i=0;i<n;i++)            cout<<a[i].pos<<' ';        cout<<endl;*/        int ans=0,anspos;        dp[0]=1;        for (int i=0;i<n;i++)        {            int Max=0;            for (int j=0;j<i;j++)            {                if (a[i].pos>a[j].pos && dp[j]>Max && a[i].num>a[j].num) //注意a[i].num>a[j].num由于排序后可能出现相同的数字连在一起的情况,不满足严格单调递增                {                    pre[i]=j;                    Max=dp[j];                }            }            dp[i]=Max+1;            if (dp[i]>ans)            {                ans=dp[i];                anspos=i;            }        }        printf("%d ",ans);        int cnt=0,xx=anspos;        while (xx!=-1)        {            //cout<<xx<<endl;            rec[cnt++]=a[xx].num;            xx=pre[xx];        }        for (int i=cnt-1;i>=0;i--)        {            printf("%d ",rec[i]);      //每个数字后都要有空格!        }        cout<<endl;    }    return 0;}