最长上升子序列(HDU 1423,PKU 1887,ZJU1986)(c++) 可输出序列

本文介绍最长上升子序列问题的两种算法实现:O(n^2)的动态规划方法与O(n*logn)的二分查找及贪心策略,并提供具体代码实例。同时探讨如何输出最长上升子序列。

最长上升子序列(HDU 1423, PKU 1887,ZJU1986)

假如序列为3 2 8 6 7 4 5 7 3,求最大上升子序列:

传说中O(n^2)算法,一般人能想到(DP)

for (i=0;i<n;i++)

    {

        max=0;

         for (j=0;j<i;j++)

             if ((a[i]>=a[j]) &&(max<d[j]))max=d[j];

         d[i]=max+1;

         if (fmax<d[i]) fmax=d[i];

    }

    printf("%d",fmax);

传说中O(n*logn)算法,节约时间空间……

(二分查找和贪心)

数组实现:

const int N = 40001;

int a[N], D[N], n;

void DP ( )

{

        scanf("%d", &n);

        int i, len = 0;

        for ( i = 0; i < n; i++ )

        scanf("%d", &a[i]);

        memset(D, 0, sizeof(D));

        int m, l, r;

        for ( i = 0; i < n; i++ )

              if ( a[i] > D[len] )

                      D[++len] = a[i];

              else

              {

                      l = 0, r = len;

                      while ( l < r - 1 )

                      {

                              m = (l + r) / 2;

                              if ( a[i] >D[m] )

                                      l = m;

                              else

                                      r = m;

                        }

                      if ( a[i] < D[l] )

                              D[l] = a[i];

                      else

                              D[r] = a[i];

              }

              printf("%d/n", len);

}

(需要注意的是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列,用堆栈实现的原理相同,但用堆来优化的话还没搞懂最后怎样把序列输出来)

 

 

 

那如果要输出序列呢?

是不是单单用数组D呢?

不是的,以3 2 8 6 7 4 5 7 3为例,D数组是2 3 5 7,这显然不对,因为在计算中我们只是取单组最大的值来保存长度,所以,要输出序列就要在中间保存一下:

#define MAX 40005

inta[MAX],b[MAX],p,n,D[MAX],Left,Right,mid,blen,num;

void DP()

{

         blen = 0;

    int i;

         scanf("%d",&p);

         for (i = 1;i <= p;i++)

                   cin>>numbers[i];

         int ans = b[1];

         for (i = 1;i <= p;i++)

         {

                   num =a[i];

                   Left = 1;

                   Right = blen;

                   while (Right >= Left)

                   {

                            mid = (Left + Right)/2;

                            if (D[mid] >= num)

                                     Right = mid - 1;

                            else

                                     Left = mid + 1;

                   }

                   b[i] = Left;

                   D[Left] = num;

                   if (Left > blen)   //check if the blen should plus one itself

                            blen = Left;

                   if (ans < b[i])

                            ans = b[i];

         }

         printf("%d/n",ans);

}

这里的的D[]就保存了每个结尾的最大子序列长度

b   :    01 12 2 3 2342

a   :    03 2 8 6 7 4 5 7 3

用b从后往前就可以看到最大上升子序列了

 

(欢迎大家指正  资料参考部分模板 )

 

天梯赛使用 OMS 监考系统,需要将参赛队员安排到系统中的虚拟赛场里,并为每个赛场分配一位监考老师。每位监考老师需要联系自己赛场内队员对应的教练们,以便发放比赛账号。为了尽可能减少教练和监考的沟通负担,我们要求赛场的安排满足以下条件: 每位监考老师负责的赛场里,队员人数不得超过赛场规定容量 C; 每位教练需要联系的监考人数尽可能少 —— 这里假设每所参赛学校只有一位负责联系的教练,且每个赛场的监考老师都不相同。 为此我们设计了多轮次排座算法,按照尚未安排赛场的队员人数从大到小的顺序,每一轮对当前未安排的人数最多的学校进行处理。记当前待处理的学校未安排人数为 n: 如果 n≥C,则新开一个赛场,将 C 位队员安排进去。剩下的人继续按人数规模排队,等待下一轮处理; 如果 n<C,则寻找剩余空位数大于等于 n 的编号最小的赛场,将队员安排进去; 如果 n<C,且找不到任何非空的、剩余空位数大于等于 n 的赛场了,则新开一个赛场,将队员安排进去。 由于近年来天梯赛的参赛人数快速增长,2023年超过了 480 所学校 1.6 万人,所以我们必须写个程序来处理赛场安排问题。 输入格式: 输入第一行给出两个正整数 N 和 C,分别为参赛学校数量和每个赛场的规定容量,其中 0<N≤5000,10≤C≤50。随后 N 行,每行给出一个学校的缩写(为长度不超过 6 的非空小写英文字母串)和该校参赛人数(不超过 500 的正整数),其间以空格分隔。题目保证每所学校只有一条记录。 输出格式: 按照输入的顺序,对每一所参赛高校,在一行中输出学校缩写和该校需要联系的监考人数,其间以 1 空格分隔。 最后在一行中输出系统中应该开设多少个赛场。 输入样例: 10 30 zju 30 hdu 93 pku 39 hbu 42 sjtu 21 abdu 10 xjtu 36 nnu 15 hnu 168 hsnu 20 输出样例: zju 1 hdu 4 pku 2 hbu 2 sjtu 1 abdu 1 xjtu 2 nnu 1 hnu 6 hsnu 1 16
最新发布
05-31
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值