http://poj.org/problem?id=3666
Making the Grade
给定一个正整数数列,要求通过对每一个元素加上或减去任意值,使得数列非严格递增(虽然题设要求还可以非严格递减,但是实际数据只要求非严格递增)。
求所得数列与原数列各个对应元素差的绝对值之和的最小值。
解题报告
思路
由于要求最终改变的绝对值和最小,所以可以知道所得解的数列中元素的最大值即原数列arr的最大值。
以此类推,所得解的数列中,每个元素必然取自原数列arr。
那么可将原数列进行排序,得到可取值数列num。
若依次对数列的每个元素进行修改,那么修改第i个数的值后的总代价仅仅与修改至第i-1个数的总代价有关。
而修改可取的值均来自num,则有状态转移方程:
修改arr[i]为num[j]后的总代价为:dp[i][j] = abs(arr[i] - num[j]) + min( dp[i-1][0], d[[i-1][1], ... , dp[i-1][j] )
代码
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int maxn = 2003; int a[maxn], b[maxn]; int num[maxn]; int dp[maxn][maxn]; int n; int Work(int *arr){ int last = arr[0]; int minNum; for(int i=1; i<=n; i++){ dp[0][i] = 0; } for(int i=1; i<=n; i++){ minNum = dp[i-1][1]; for(int j = 1; j<=n ; j ++){ minNum = min(dp[i-1][j], minNum); dp[i][j] = abs(arr[i] - num[j]) + minNum; } } int ans = dp[n][1]; for(int i=1; i<=n; i++){ ans = min(dp[n][i], ans); } return ans; } int main(){ while(cin >> n){ for(int i=1; i<=n; i++){ cin >> a[i]; num[i] = a[i]; b[n-1-i] = a[i]; } sort(num+1, num+n+1); cout << Work(a)<< endl; } return 0; }
--(完)--