poj 1836 Alignment
http://poj.org/problem?id=1836
题意:
一队士兵排队,高低起伏。去掉最少的士兵,使得中间高两边低(单峰)。
经典LIS,注意[1~n]的最优解并不一定在dp[n]中,故需预处理。
1 #include <iostream> 2 #include <stdio.h> 3 #include <string> 4 #include <string.h> 5 #include <stdlib.h> 6 #define EPS 1e-5 7 #define INF 0x3f3f3f 8 9 using namespace std; 10 int ans, n; 11 double num[1005]; 12 int dpI[1005], dpD[1005]; 13 14 void LIS(int a, int b) 15 { 16 for(int i=a; i<=b; i++) 17 dpI[i] = 1; 18 19 for(int i=a; i<=b; i++) 20 { 21 for(int j=a; j<i; j++) 22 if(num[j]-num[i] <= -EPS) //即num[j]<num[i] 23 dpI[i] = max(dpI[i], dpI[j]+1); 24 } 25 } 26 27 void LDS(int a, int b) 28 { 29 for(int i=a; i<=b; i++) 30 dpD[i] = 1; 31 32 for(int i=b; i>=a; i--) 33 { 34 for(int j=b; j>i; j--) 35 if(num[j]-num[i] <= -EPS) //即num[j]<num[i] 36 dpD[i] = max(dpD[i], dpD[j]+1); 37 } 38 } 39 40 void print(int *num) 41 { 42 for(int i=0; i<n; i++) 43 cout << num[i] << " "; 44 cout << endl; 45 46 } 47 int main() 48 { 49 //freopen("testin.txt", "r", stdin); 50 //freopen("testUout.txt", "w", stdout); 51 52 while(cin >> n) 53 { 54 //dpI[i]为包含num[i]的上升子序列的最大值。 55 for(int i=0; i<n; i++) 56 scanf("%lf", &num[i]); 57 58 LIS(0, n-1); 59 LDS(0, n-1); 60 61 //预处理!!! 62 for(int i=1; i<=n-1; i++) 63 dpI[i] = max(dpI[i], dpI[i-1]); 64 for(int i=n-2; i>=n; i++) 65 dpD[i] = max(dpD[i], dpD[i+1]); 66 //print(dpI); 67 //print(dpD); 68 ans = 0x3f3f3f; 69 for(int i=0; i<n-1; i++) 70 ans = min(ans, n - dpI[i] - dpD[i+1]); 71 printf("%d\n", ans); 72 } 73 74 return 0; 75 }