大致題意:給出一隊士兵的身高,一開始不是按身高排序的。要求最少的人出列,使原序列的士兵的身高先遞增後遞減。
求遞增和遞減不難想到遞增子序列,要求最少的人出列,也就是原隊列的人要最多。
1 2 3 4 5 4 3 2 1
這個序列從左至右看前半部分是遞增,從右至左看前半部分也是遞增。所以我們先把從左只右和從右至左的LIS分別求出來。
如果結果是這樣的:
A[i]={1.86 1.86 1.30621 2 1.4 1 1.97 2.2} //原隊列
a[i]={1 1 1 2 2 1 3 4}
b[i]={3 3 2 3 2 1 1 1}
如果是A[1]~A[i]遞增,A[i+1]~A[8]遞減。此時就是求:a[1]~a[i]之間的一個值與b[i+1]~b[8]之間的一個值的和的最大值。
O(n^2)和O(nlogn)算法都可以過。
O(n^2)算法:
#include <iostream> #include <cstdio> using namespace std; const int Max=1e3+5; int main() { //freopen("in.txt","r",stdin); int n; scanf("%d",&n); double a[Max]={0}; for(int i=0; i<n; i++) scanf("%f",a+i); int l[Max]= {0},r[Max]= {0}; l[0]=r[n-1]=1; for(int i = 1; i < n; i++) { int maxLen = 0; for(int j = 0; j < i; j++) if(a[j]<a[i]) maxLen = max(maxLen,l[j]); l[i] = maxLen + 1; } for(int i=n-2; i>=0; i--) { int maxLen=0; for(int j=n-1; j>i; j--) if(a[j]<a[i]) maxLen=max(maxLen,r[j]); r[i]=maxLen+1; } int maxlen=0; for(int i=0;i<n-1;i++) for(int j=i+1;j<n;j++) maxlen=max(maxlen,l[i]+r[j]); printf("%d\n",n-maxlen); return 0; }
O(nlogn)算法
#include <iostream> #include <cstdio> using namespace std; const int Max=1e3+5; int l[Max]= {0},r[Max]= {0}; double B[Max]; int BinarySearch(double *a, double value, int n) { int low = 0; int high = n - 1; while(low <= high) { int mid = (high + low) / 2; if(a[mid] == value) return mid; else if(value<a[mid]) high = mid - 1; else low = mid + 1; } return low; } int LIS_DP_NlogN(double *a, int n,int *Len) { int nLISLen = 1; B[0] = a[0]; for(int i = 1; i < n; i++) { if(a[i] > B[nLISLen - 1]) { B[nLISLen] = a[i]; nLISLen++; Len[i]=nLISLen; } else { int pos = BinarySearch(B, a[i], nLISLen); B[pos] = a[i]; Len[i]=pos+1; } } return nLISLen; } int main() { //freopen("in.txt","r",stdin); int n; scanf("%d",&n); double a[Max]={0}; double b[Max]={0}; l[0]=r[0]=1; for(int i=0; i<n; i++) { scanf("%f",a+i); b[n-i-1]=a[i]; } LIS_DP_NlogN(a,n,l); LIS_DP_NlogN(b,n,r); int maxlen=0; for(int i=0;i<n-1;i++) for(int j=n-i-2;j>=0;j--) maxlen=max(maxlen,l[i]+r[j]); printf("%d\n",n-maxlen); return 0; }