大致題意:給出一隊士兵的身高,一開始不是按身高排序的。要求最少的人出列,使原序列的士兵的身高先遞增後遞減。
求遞增和遞減不難想到遞增子序列,要求最少的人出列,也就是原隊列的人要最多。
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;
}