poj-3666 Making the Grade

呂振麒 bio photo By 呂振麒 Comment

傳送門:

Making the Grade

題意:

給 N 個數字,改動每個數字要花費 Ai-Ai’ ,將這 N 個數字修改成非嚴格遞增或遞減的數列,需要的最小花費是?

思路:

觀察發現,一個數字一定只會不改動或改成其他數列中的數字。
現在思考,數列一個一個數字加入時,只能在前一個數字為某些特定值,才能夠造出一個合法數列。所以我們要把數列中,第 i 個位置更改成 Ai’ 且前 i 個都合法時的情況的花費都算好,這樣才能計算第 i+1 個位置。

共有 N*N 個狀態,可以使用一些技巧來壓縮空間 (滾動陣列)、時間 (漸進式優化) 複雜度。

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <cstdio>
#include <vector>
#include <algorithm>

using namespace std;

const int mxn = 2002;

int N, n;
vector<int> v, v2, dp[2];

inline int dis(int a, int b) {
  return abs(v[a] - v2[b]);
}

int main() {
  scanf("%d", &N);
  v.resize(N);
  for(int i=0; i<N; ++i)
    scanf("%d", &v[i]);
  v2 = v;
  sort(v2.begin(), v2.end());
  v2.resize(unique(v2.begin(), v2.end()) - v2.begin());
  n = v2.size();

  dp[0].resize(N);
  dp[1].resize(N);

  for(int i=0; i<N; ++i) {
    for(int j=0; j<n; ++j) {
      dp[1][j] = dis(i, j);
      if(i) dp[1][j] += dp[0][j];
      if(j) dp[1][j] = min(dp[1][j], dp[1][j-1]);
    }
    swap(dp[0], dp[1]);
  }
  int ans = dp[0][n-1];
  for(int i=0; i<N; ++i) {
    for(int j=n-1; j>=0; --j) {
      dp[1][j] = dis(i, j);
      if(i) dp[1][j] += dp[0][j];
      if(j+1<n) dp[1][j] = min(dp[1][j], dp[1][j+1]);
    }
    swap(dp[0], dp[1]);
  }

  printf("%d\n", min(ans, dp[0][n-1]));
}
comments powered by Disqus