大前端

前端学习之家-大前端

【DP周】- 第一周(基础DP) - day4 - Making the Grade

Making the Grade
在这里插入图片描述

分析:
要想找到最低成本那么处理过后的上升或者下降的序列一定是原序列中的值
那么这样
我们就可以先将原序列排好序得到字符串b
现在原字符串中的元素的状态就是在字符串b中第1~n一共n中状态
所以
我们可以列出状态转移方程
表示前i个元素在字符串b中位置为j时的最低成本
那么在找前i个元素在j位置时的最低成本的前提下,要找到前i - 1个元素在什么位置有最低成本
v = f[i - 1][1]
v = max(v, f[i - 1][j])
之后再加上a[i] 到 b[i] 的花费即f[i][j]
dp[i][j] = abs(a[i] - b[j]) + v
注意
abs只适用于int类型,定义的longlong要自己定义个abs函数,否则会编译错误(别问我是怎么知道的)
最后
上面描述的时上升序列,下降序列只有排序的时候不同。

#include <iostream>
#include <algorithm>
 
#define ll long long
#define Abs(a) ((a) > 0 ? (a) : -(a))
using namespace std;

const int N = 2021;
int n;
ll a[N];
ll b[N];
ll dp[N][N];


bool cmp(ll a, ll b)
{
	return a > b;
}
ll up()
{
	sort(b + 1, b + n + 1);	
	
	for(int i = 1; i <= n; i ++)
	{
		ll v = dp[i - 1][1]; // 前i - 1个序列位置在b序列的1处的最小cost 
		
//		cout << v << "**" <<endl;
		for(int j = 1; j <= n; j ++)
		{
			v = min(v, dp[i - 1][j]);
			dp[i][j] = Abs(a[i] - b[j]) + v;
		}	
	}
	ll ans = dp[n][1];
	for(int i = 1; i <= n; i ++)
		ans = min(ans, dp[n][i]);
	
	return ans; 
} 
ll down()
{
	sort(b + 1, b + n + 1, cmp);
	for(int i = 1; i <= n; i ++)
	{
		ll v = dp[i - 1][1]; // 前i - 1个序列位置在b序列的0处的最小cost 
		for(int j = 1; j <= n; j ++)
		{
			v = min(v, dp[i - 1][j]);
			dp[i][j] = Abs(a[i] - b[j]) + v;
		}	
	}
	ll ans = dp[n][1];
	for(int i = 1; i <= n; i ++)
		ans = min(ans, dp[n][i]);
	
	return ans; 
}
int main() 
{
	cin >> n;
	for(int i = 1; i <= n; i ++)
		cin >> a[i], b[i] = a[i]; // 离散化 将a的值缩小在n的范围内 
		
	cout << min(up(), down()) << endl;

}

发表评论:

Copyright Your WebSite.Some Rights Reserved.