題目在此數組
解題思路:這題出得有點偏離實際,可是呢,編故事原本就是爲了豐富題目的,無論它了。.net
這題的本質是:給定一個序列,去掉一些項使其成爲先遞增後遞減的子序列,求去掉項的最小數目。code
初看起來好像有點複雜,但問題每每是換個角度想就一下變簡單了。去項很差求,就求保留項好了。如此,這個問題就轉變成了求給定序列的先遞增後遞減子序列的最大長度,去項的最小數目 = 序列長度 N - 符合要求序列的最大長度。blog
具體步驟:將原序列 [0...N) 從 i (1 <= i <= n - 2) 處一分爲二,求 [0...i](遞增)與 (i...N)(遞減)子序列長度的最大和,此即爲符合要求的最長序列。至於最長遞增/遞減子序列的求法,固然用動規了(參見 POJ 2533: Longest Ordered Subsequence)。get
代碼:io
#include <cstdio> const int MAX = 1001; float a[MAX]; int asc[MAX], des[MAX]; void solve(int n) { int ans = 0; // 計算最長遞增子序列狀態數組 for (int i = 0; i < n; ++i) { asc[i] = 1; for (int j = i - 1; j >= 0; --j) { if (a[i] > a[j] && asc[j] + 1 > asc[i]) { asc[i] = asc[j] + 1; } } } // 計算最長遞減子序列狀態數組 for (int i = n - 1; i >= 0; --i) { des[i] = 1; for (int j = i + 1; j < n; ++j) { if (a[i] > a[j] && des[j] + 1 > des[i]) { des[i] = des[j] + 1; } } } // 從 i 處分開,[0...i] 的最長遞增序列長度 + (i...N) 最長 // 遞減序列長度 = 最長先遞增後遞減序列的長度 for (int i = 0; i < n - 1; ++i) { for (int j = i + 1; j < n; ++j) { if (asc[i] + des[j] > ans) { ans = asc[i] + des[j]; } } } // 用 N 減去最長序列長度即爲要去掉的最小項數 printf("%d\n", n - ans); } int main() { int n; while (scanf("%d", &n) != EOF) { for (int i = 0; i < n; ++i) { scanf("%f", &a[i]); } solve(n); } return 0; }