lintcode91:最小调整代价
给一个整数数组,调整每个数的大小,使得相邻的两个数的差不大于一个给定的整数target,调整每个数的代价为调整前后的差的绝对值,求调整代价之和最小是多少。
例如:对于数组[1, 4, 2, 3]和target=1,最小的调整方案是调整为[2, 3, 2, 3],调整代价之和是2。返回2。
例如:对于数组[1, 5, 6]和target=1,最小的调整方案为[4,5,6],调整代价之和是3.返回3.
思路分析:
如何去构造最优子结构?如何存放数据?
对于这些问题,我想了一个小时,也没有想出个所以然。先说一下我自己的理解,开始的时候没有读清题意,认为修改一次的代价是1,1->2代价为1,2->5代价为1.印象中依稀记得动态规划算法实际上是对穷举法的变形。而具有n个数据的数组,最大的调整次数是n,最小的调整次数是0;如果采用穷举法,一共有2^n-1中可能。思路之后就断开了,如何存储数据,使用一维数组表示调整的次数,或者是使用二维数组,那么二维数组表示的是什么意思呢?带着这些疑问,我决定看一下别人的思路。
百度搜索到了解决问题的方法,涉及的陌生名词一共有3个。动态规划、滚动数组、记忆搜索。
如何存放数据?
建立一个二维数组M[A.size()][100],A.size()表示数组的大小,其中100表示0-99的100中可能。
M[i][j]表示的值的含义是第i个数据调整成j使用的最小调整次数,前面的i-1个数据已经最小的方式了。
如果构造最优子结构?
m[i][j] = min{ m[i-1][k]+abs(A[i]-j)/0 //其中k的取值是j-target到j+target };
一共需要三次循环,最外层循环A.size()次,中间循环100次,第三次循环2*target次
过程中的问题:知道思路之后写这个程序还是花了很长的时间,大约一个多小时。主要的原因是不明白m[i][j]是什么意思。此处说明一下,m[i][j]表示的含义是第i个数据,如果是j需要调整的最少次数。数据从i-1个到i个有意义的条件是A[i-1]和A[i]的绝对值之差小于target。(A表示数据)
代码如下
#include <vector>
#include <iostream>
#include <sstream>
#include <queue>
#include <cmath>
#include <climits>
using namespace std;
class Solution {
public:
int MinAdjustmentCost(vector<int> &A, int target) {
if(A.size() == 1 || A.size() == 0)
{
return 0;
}
//建立存放的容器
int ** m = new int* [A.size()];
for(int i = 0 ; i < A.size() ; i++)
{
m[i] = new int[100];
}
//初始化数据
for(int i = 0 ; i < 100 ;i ++)
{
m[0][i] = abs(i-A.at(0));
}
//循环获取数据
int min;
int min_j;
for(int i = 1 ; i < A.size() ;i++)
{
min_j = 100000;
for(int j = 0 ; j < 100 ; j++)
{
min = 100000;
//并不是全部位置可能只有一部分。
for(int z = -target ; z < target+1 ; z++)
{
//如果相差的数据,在target之内,不需要修改数据
if(z+j < 0 || z+j >= 100)
{
continue;
}
if(min > m[i-1][z+j] + abs(j-A.at(i)))
{
min = m[i-1][z+j] + abs(j-A.at(i));
}
}
m[i][j] = min;
if(m[i][j] < min_j)
{
min_j = m[i][j];
}
}
}
//最后的答案就是min;
return min_j;
}
};
int main()
{
vector<int> vec;
vec.push_back(1);
vec.push_back(100);
//vec.push_back(6);
Solution s;
cout << s.MinAdjustmentCost(vec,79);
return 0;
}