Making the Grade 【dp】

A straight dirt road connects two fields on FJ’s farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).

You are given N integers A1, … , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . … , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is

|A1 - B1| + |A2 - B2| + … + |AN - BN |
Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer.

Input

  • Line 1: A single integer: N
  • Lines 2…N+1: Line i+1 contains a single integer elevation: Ai

Output

  • Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.

Sample Input

7
1
3
2
4
5
3
9

Sample Output

3

翻译

一条笔直的土路连接着FJ农场的两块田地,但它改变的海拔比FJ想要的还要高。他的奶牛不介意爬上或爬下一个斜坡,但它们不喜欢交替的山丘和山谷。FJ希望添加和清除道路上的污垢,使其成为一个单调的斜坡(向上)。

给定N个整数A1,安(1)≤ N≤ 2000)描述高程(0≤ 艾岛≤ 1000000000)在道路上N个等距位置处,从第一个场地开始,到另一个场地结束。FJ希望将这些高程调整为新的序列B1,非递增的BN。由于在道路沿线任何位置添加或清除污垢的费用相同,因此改造道路的总费用为

|A1-B1 |+| A2-B2 |+…+|AN-BN|

请计算平整道路的最低成本,使其成为连续坡度。FJ很高兴地告诉您,有符号32位整数当然可以用来计算答案。

注意:我认为二维dp更好理解

代码(一维dp)

#include "stdio.h"
#include "algorithm"
using namespace std;
#include "math.h"
#define ll long long
int dp[2009];
int a[2009],b[2009];
int main()
{
    
    
	int i,j,k,l,n,m;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	{
    
    
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(a+1,a+n+1);
	for(i=1;i<=n;i++)
	{
    
    
		k=1000000000;
		for(j=1;j<=n;j++)
		{
    
    
			k=min(k,dp[j]);
			dp[j]=k+abs(b[i]-a[j]);
		}
	}
	k=1000000000;
	for(i=1;i<=n;i++)
	k=min(k,dp[i]);
	printf("%d\n",k);
}

一维dp代码的理解

以题上的例子举例,我们把for循环的东西写出来

i i=1 i=2 i=3 i=4 i=5 i=6 i=7
数组a 1 3 2 4 5 3 9
数组b 1 2 3 3 4 5 9

为什么我们要给b数组从小到大排序了?
我们可以因为我们的场地是非递减的的形式,我们现在所认为的最优为,排列后的b数组

我们把for循环的东西,写出dp[]的值

j\i i=1 i=2 i=3 i=4 i=5 i=6 i=7
j=1 0 1 2 2 3 4 8
j=2 2 1 0 0 1 2 6
j=3 3 1 1 1 2 3 7
j=4 6 3 2 2 1 2 6
j=5 10 6 4 4 2 2 5
j=6 12 7 4 4 3 4 8
j=7 20 14 10 10 8 7 3

我们就看i=1,这一列的值,最后j=7时,dp=20(这里的dp为dp[1],我们解释时[1]不重要,后面我就不带了),这个值是什么意思了,我们想想:(i=1,j=1时,dp=0(1–>1,消耗为0),i=1,j=2时,dp=2(3–>1,消耗为2),i=1,j=3时,dp=3(2–>1 + 3–>1,消耗为1+2=3),以此类推
i=1,j=7时 :我们把所有的场地的高度改成1时,最低成本为20;

我们再算算i=2,j=2时,dp=1,是怎么来的,是由i=1,j=1时的dp+abs(a[2]-b[2])得来的,从这儿我们可以得出,

i=1这一列意味着 所有场地以b[1]=1为基地,最小消耗量
i=2这一列意味着 所有场地以b[1]=1和b[2]=2为基地,最小消耗量
…… …… …………

代码(二维dp)

#include "stdio.h"
#include "algorithm"
#include "string.h"
#include "math.h"
using namespace std;
#define ll long long
#define inf 0X3f3f3f3f
int dp[2009][2009],a[2009],b[2009];
int main()
{
    
    
	int n,i,j,k,l;
	scanf("%d",&n);
	for(i=1; i<=n; i++)
	{
    
    
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	memset(dp,inf,sizeof(dp));
	for(i=0; i<=n; i++)
		dp[i][0]=0;
	for(i=1; i<=n; i++)
	{
    
    
		for(j=1; j<=n; j++)
		{
    
    
			l=min(dp[i][j-1],dp[i-1][j-1]);
			dp[i][j]=min(dp[i-1][j],l+abs(b[i]-a[j]));
		}
	}
	printf("%d\n",dp[n][n]);
}

猜你喜欢

转载自blog.csdn.net/weixin_53623850/article/details/120598464
今日推荐