POJ 1836 双边最长上升子序列

马草AC了简直是各种爽啊,而且算法里只用了两次LIS,算法整体复杂度O(nlogn)

真的是应了老乔那句至简至繁至简,思考了一整天,还是直接用两次LIS外加两个辅助数组就解决了问题

思路就是,要真的深入地思考清楚这个问题,真的深入理解了LIS而不仅仅是套模板,套模板的结果就是把复杂度弄成O(n^2logn)

首先一点,题目要求是,只要最终队列里的人能够看到队列两端的至少一端。

其次,一个细节问题需要注意,队列中最高的人可以有两个,如下图

接下来就是具体算法了,思路就是枚举每一个士兵arr[i], 看要剔除多少个人才能形成上图所示队列;

然后选出剔除人数最少的那一种。

arr[0] ... arr[i] ... arr[i+1] ... arr[n-1]

也就是说,对于arr[i],分别要对arr[0] ... arr[i] 和 arr[n-1] ... arr[i+1] 进行一次LIS,并且LIS的过程中每个士兵的height都不能超过arr[i]的height    ———思路1

如果不再深入思考的话,根据这个思路算法看起来就是,一层循环,循环里套两个LIS,这也是网上大多数人的做法

但是我要告诉你,两次LIS外加两个数组记录状态就OK了,之后再用一个循环去结果里找出最佳的结果      ———思路2

你真的理解LIS了麽?

在一次队列的LIS中,当LIS进行到arr[i]的时候,LIS的结果数组res中已经记录了arr[0]到arr[i-1]LIS的结果

所以处理arr[i]的时候,是不是用数组记录一下LIS中二分的结果,就是思路1的循环中的LIS想要的结果呢?

如果看懂这一句话的时候,你就可以直接看我的代码了

  1 #include<stdio.h>
  2 #include<iostream>
  3 using namespace std;
  4 
  5 #include<math.h>
  6 #include<algorithm>
  7 #include<string.h>
  8 #include<stdlib.h>
  9 #include<vector>
 10 #include<set>
 11 #include<map>
 12 #include<stack>
 13 #include<string>
 14 #include<queue>
 15 
 16 #define repA(p,q,i)  for( int (i)=(p); (i)!=(q); ++(i) )
 17 #define repAE(p,q,i)  for( int (i)=(p); (i)<=(q); ++(i) )
 18 #define repD(p,q,i)  for( int (i)=(p); (i)!=(q); --(i) )
 19 #define repDE(p,q,i)  for( int (i)=(p); (i)>=(q); --(i) )
 20 
 21 double arr[1010];
 22 double res[1010];
 23 
 24 int LFarr[1010];
 25 int RGarr[1010];
 26 
 27 void INC(int n);
 28 void DEC(int n);
 29 
 30 int main()
 31 {
 32     int n;
 33     while( scanf("%d", &n) != EOF )
 34     {
 35            repA(0, n, i)
 36              scanf("%lf", &arr[i]);
 37            
 38            INC(n);
 39            DEC(n);
 40            int result = -0x3f3f3f3f;
 41            repA(0, n, i)
 42              result = max(result, LFarr[i]+RGarr[i]); 
 43              //printf("%d  %d\n", LFarr[i], RGarr[i]);
 44            
 45            printf("%d\n", n-result);
 46                   
 47     }
 48     return 0;    
 49 }
 50 
 51 void INC(int n)
 52 {
 53     int rd,lf, rg, mid;
 54     rd = 0; res[0] = arr[0];
 55     
 56     repA(0, n, i)
 57     {
 58             if( arr[i] > res[rd] )
 59             {
 60                 res[++rd] = arr[i];
 61                 LFarr[i] = rd+1;    
 62             }
 63               
 64             else{
 65                  lf = 0;  rg = rd;
 66                  while(rg >= lf)
 67                  {
 68                           mid = (rg+lf)/2;
 69                           if(res[mid] == arr[i])
 70                           {  lf=mid;  break;  }
 71                           else if(res[mid] > arr[i])
 72                             rg = mid-1;
 73                           else lf = mid+1;             
 74                  }
 75                  res[lf] = arr[i];
 76                  LFarr[i] = lf + 1;   
 77             }
 78                       
 79     }    
 80     
 81     return ;
 82 }
 83 
 84 
 85 void DEC(int n)
 86 {   
 87     int rd,lf, rg, mid;
 88     rd = 0; res[0] = arr[n-1];
 89     RGarr[n-1] = 0;
 90     
 91     repDE(n-2, 0, i)
 92     {
 93             if( arr[i] > res[rd] )
 94             {
 95                 res[++rd] = arr[i];
 96                 RGarr[i] = rd;    
 97             }
 98               
 99             else{
100                  lf = 0;  rg = rd;
101                  while(rg >= lf)
102                  {
103                           mid = (rg+lf)/2;
104                           if(res[mid] == arr[i])
105                           {  lf=mid;  break;  }
106                           else if(res[mid] > arr[i])
107                             rg = mid-1;
108                           else lf = mid+1;             
109                  }
110                  RGarr[i] = lf;
111                  if(res[lf] == arr[i])
112                    ++RGarr[i];
113                  
114                  res[lf] = arr[i]; 
115             }
116     }   
117     
118     return ;    
119 }
View Code

 

posted on 2014-06-12 10:00  码农之上~  阅读(259)  评论(0编辑  收藏  举报

导航