Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65351
  • 博文数量: 115
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 10
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-08 19:09
文章分类
文章存档

2015年(115)

我的朋友

分类: C/C++

2015-08-06 16:41:59


热乎出炉的斯伦贝谢今年(2015)校招的机试中的一道。online judge模式。内人去笔试,结果虐的体无完肤。好像是3小时5道题。题目并不新感觉比较中正平和,也能充分考察出功底。

题目是老题,没太多可说的。刷刷题,阴郁的心情能好一点。

题目:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使 得剩下的K位同学排成合唱队形。   合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK,  则他们的身高满足T1<...Ti+1>…>TK(1<=i<=K)。   你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

解析:
1. 对于解: T1<...Ti+1>…>TK 来说, Ti左边(包括Ti)为递增序列,Ti右边为递减序列
2. 设函数f(x) 为 T0~ Tx这个序列中 包含x的最长递增子序列

3. 设函数g(x) 为 Tx~T(n-1)这个序列中 包含x的最长递减子序列
4. 根据以上假设,对于x 包含x的最长的,符合条件的合唱团序列 h(x) = f(x) + g(x) -1
5. 最终,需要去除的最少人的个数为K = N - max(h(x)) x∈(0,N-1)

a. 对于函数f(x),有
f(x) = max( f(i)) + 1  其中i∈(0,x-1) 且Ti 伪代码:
  f(x) = 0;
  for  i  in ( 0 .. x-1){
         if ( Ti< Tx and  and f(x)                f(x) = f(i);
         }
  }
  f(x) +=1;


b.对于函数g(x), 偷懒的办法就是可以把输入倒过来,用f(x)算一遍,然后将结果倒过来就好了。
当然,两次翻转会增加O(n)的复杂度。你也可以选择把f(x)的条件倒过来。

c.如果说我们需要输出最后的结果序列,我们就需要额外的空间来存储每步的结果。
对于f(x) ,我们返回两个值  f(x) = maxlen, prev
maxlen为包含Tx的最长递增子序列的长度
prev为包含Tx的最长递增子序列中Tx的前一个元素
类似链表的结构,最后可以方便的输出结果。
(示例代码中未实现该部分)


下面的代码中,采取了折衷的方法,将输入倒了过来,只不过最后求最大值的时候用对len取补的方法处理了下标。

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. void fun(int *input, int size, int* result){
  4.     result[0] = 1;
  5.     int i;
  6.     for(i = 1; i<size; i++){
  7.          int j = 0;
  8.          int tmax = 0;
  9.          for(;j<i;j++){
  10.              if(input[j]<input[i] && tmax < result[j]){
  11.                  tmax = result[j];
  12.              }
  13.              result[i] = tmax + 1;
  14.          }
  15.     }
  16. }

  17. void rev(int* input , int size){
  18.    int start = 0;
  19.    int end = size -1;
  20.    while( start<end){
  21.         int tmp = input[start];
  22.         input[start] = input[end];
  23.         input[end] = tmp;
  24.         start ++;
  25.         end --;
  26.    }
  27. }

  28. int main(){
  29. int input[] = {1,2, 5, 1,2, 3};
  30. int len = sizeof(input)/sizeof(int);

  31. int left[len];
  32. int right[len];
  33. fun(input, len , left);
  34. rev(input,len);
  35. fun(input, len , right);
  36. int max = 0;
  37. int i;
  38. for(i = 0; i<len; i++){
  39.    //printf("num=%d : left(%d) = right(%d)\n", input[len-i-1],left[i],right[len-i-1]);
  40.    if (max< left[i] + right[len-i-1] - 1)
  41.        max = left[i] + right[len-i-1] -1 ;
  42. }
  43. printf("%d\n", len - max);
  44. }











阅读(190) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~