Problem B. Make it Smooth
Problem
You have a one-dimensional array of N pixels. Each pixel has a value, represented by a number between 0 and 255, inclusive. The distance between two pixels is the absolute difference of their numbers.
You can perform each of the following operations zero or more times:
- With cost D, delete any pixel, so its original neighbors become neighboring pixels.
- With cost I, insert one pixel of any value into any position -- either between two existing pixels, or before the first pixel, or after the last pixel.
- You can change the value of any pixel. The cost is the absolute difference of the old value of the pixel and the new value of the pixel.
The array is smooth if any neighboring pixels have distance at most M. Find the minimum possible cost of a sequence of operations that makes the array smooth.
Note: The empty array -- the array containing no pixels -- is considered to be smooth.
Input
The first line of the input gives the number of test cases, T. T test cases follow, each with two lines. The first line is in the form "D I M N", the next line contains N numbers ai: the values of the pixels from left to the right.
Output
For each test case, output one line containing "Case #x: y", where x is the case number (starting from 1), and y is the minimum cost to make the input array smooth.
Limits
All the numbers in the input are integers.
1 ≤ T ≤ 100
0 ≤ D, I, M, ai ≤ 255
Small dataset
1 ≤ N ≤ 3.
Large dataset
1 ≤ N ≤ 100.
Sample
Explanation
In Case #1, decreasing the 7 to 3 costs 4 and is the cheapest solution. In Case #2, deleting is extremely expensive; it's cheaper to insert elements so your final array looks like [1, 6, 11, 16, 21, 26, 31, 36, 41, 46, 50, 45, 40, 35, 30, 25, 20, 15, 10, 7]
.
解题思路:
最近遇到的一些动态规划问题中感觉最难的一个,思考明白后让我对动态规划的理解更深刻了。思路是这个数组中的每个数字在最小代价时,不确定大小,但是在0-255范围内把每种不同组合的情况都考虑到,找出其中最小的代价。在找的过程中,可以先找数组前1个的最小代价,然后利用前1个的结论找前2个的最小代价,也就是用动态规划的思想递归求解。在定义数组a[N],存放输入的N个记录。定义dp[N+1][256],例如dp[i+1][j]的意义是,a的子数组a[0:i]中最后一个像素变为j时的最小代价。可能的情况有:
1. 删除a[i+1],那么cost=dp[i][j] + D,即a[i]变为j的代价加上删除a[i+1]代价。
2.修改a[i+1]变为j,那么需要考虑a[i]不同情况,我们使用辅助变量k表示a[i]的不同情况,0<=k<=255。cost=dp[i][k]+insert_cost+move_cost,其中move_cost指的是将a[i+1]修改为j的代价,insert_cost指的是将k到j之间通过插入使之平滑的代价。
求出删除a[i+1]与k取不同值时修改a[i+1]的代价的最小值,即为a[i+1][j]的值。接下来只需要找出dp[N][0:255]中的最小值,即为答案。
void run() {
int COUNT = sc.nextInt();
for (int c = 0; c < COUNT; c++) {
int D = sc.nextInt();
int I = sc.nextInt();
int M = sc.nextInt();
int N = sc.nextInt();
int[] a = new int[N];
for (int i = 0; i < N; i++) {
a[i] = sc.nextInt();
}
int[][] dp = new int[N + 1][256];
for (int i = 0; i < N; i++) {
for (int j = 0; j < 256; j++) {
int tmp = dp[i][j] + D;
if (M == 0) {
tmp = min(tmp, dp[i][j] + abs(a[i] - j));
} else {
for (int k = 0; k < j; k++) {
int diff = abs(j - k);
int insert = max(diff - 1, 0) / M;
int cost = dp[i][k] + insert * I + abs(a[i] - j);
if (cost < tmp)
tmp = cost;
}
}
dp[i + 1][j] = tmp;
}
}
int min = Integer.MAX_VALUE;
for (int i = 0; i < 256; i++)
min = min(min, dp[N][i]);
System.out.println(String.format("Case #%d: %d", c + 1, min));
}
}