POJ 3666 Making the Grade(数列变成非降序/非升序数组的最小代价,dp)

传送门:

http://poj.org/problem?id=3666


Making the Grade

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 9468   Accepted: 4406

Description

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

Source

USACO 2008 February Gold

题目意思:

给出长度为n的整数数列,每次可以将一个数加1或者减1,最少要多少次可以将其变成单调增或者单调减(不严格).

参考了一下网友的思想:https://www.cnblogs.com/Philip-Tell-Truth/p/4916026.html

就是农夫要修一条路,现在要求这条路要么就是上升的,要么就是下降的,总代价为∑|a[i]-b[i]|,求代价最低的修路方案, (0 ≤ β≤ 1,000,000,000) , (1 ≤ N ≤ 2,000)

  这一题百分百就是DP了,为什么?我们现在就是要让cost最小,但是我们不知道cost应该怎么才能最小。

  我们可以这么想,因为序列总是上升或者下降的,我们可以考虑上升的情况,假设前几个数组成的最大值为β,我们要考虑从0-β的改变值,然后不断推到第n个序列。

  显然,这样的复杂度为0(Nβ^2),当然这样的复杂度显然是出事的。  

  现在我们想着优化这个东西,我们可以这么想,如果我们像之前那样扫描的话,那么其实我们忽略了一个很重要的事实,就是在变到α(α<β),其实对于α+1~β之内不会对α造成影响,于是我们可以用一个最小值的临时变量储存在α之前的最小值,用这个更新dp即可,那样就少了一次扫β的复杂度

  复杂度变为O(Nβ);

  但是如果仅仅是这样的话,绝对是TLE,因为β实在是太大了。

  那么我们就要用到离散化的思想,把β投影到有限区域中,既然β是大小的函数,那么我们把可以这样对应:我们只用把新的序列按从小到大排列,然后只对下标进行查找就可以了,这样我们就把解的空间变到下标中了。

   最后状态转移方程:dp[i-1][j]=ABS(a[i]-b[j])+min(dp[i-1][j]);(用滚动数组就可以了)

具体做法:

首先可以看出变化后的序列中所有的数一定还在原数列中,
     那么先对原数列排序

a                  b
   1 3 2 4 5 3 9 -> 1 2 3 3 4 5 9
   然后dp[i][j]  表示第i个数, 把他变成 b[j] 所要画的最小代价
   dp[i][j] = dp[i-1] [ 0~j] + abs(b[j] - a[i])   以此循环。

code:

#include<stdio.h>
#include<string.h>
#include<memory>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
#define max_v 2005
#define INF 0x7fffffff
int n;
int dp[max_v];
int e[max_v];
int b[max_v];
int main()
{
    /*
    首先可以看出变化后的序列中所有的数一定还在原数列中,
     那么先对原数列排序

        a                  b
   1 3 2 4 5 3 9 -> 1 2 3 3 4 5 9
   然后dp[i][j]  表示第i个数, 把他变成 b[j] 所要画的最小代价
   dp[i][j] = dp[i-1] [ 0~j] + abs(b[j] - a[i])   以此循环。
   */
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>e[i];
        b[i]=e[i];
    }
    sort(b,b+n);//升序之后的数组,对比e
    int ans=INF;
    int t;
    for(int i=0;i<n;i++)
    {
        t=INF;
        for(int j=0;j<n;j++)
        {
            t=min(t,dp[j]);
            dp[j]=abs(b[j]-e[i])+t;
        }
    }
    for(int i=0;i<n;i++)
    {
        ans=min(ans,dp[i]);
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/yinbiao/p/9345700.html

时间: 2024-10-07 19:23:24

POJ 3666 Making the Grade(数列变成非降序/非升序数组的最小代价,dp)的相关文章

Poj 3666 Making the Grade (排序+dp)

题目链接: Poj 3666 Making the Grade 题目描述: 给出一组数,每个数代表当前位置的地面高度,问把路径修成非递增或者非递减,需要花费的最小代价? 解题思路: 对于修好的路径的每个位置的高度肯定都是以前存在的高度,修好路后不会出现以前没有出现过得高度 dp[i][j]代表位置i的地面高度为第j个高度,然后我们可以把以前的路修好后变成非递减路径,或者把以前的路径首尾颠倒,然后修成非递减路径.状态转移方程为:dp[i][j] = min(dp[i-1][k]) + a[i] -

[2016-03-28][POJ][3666][]Making the Grade]

时间:2016-03-28 17:23:08 星期一 题目编号:[2016-03-28][POJ][3666][]Making the Grade] 分析:dp[i][j]表示把改到第i个数,且把a[i]改成b[i]需要的最少代价,已知b[j]递增,dp[i][j]由dp[i - 1][k]递推过来,如果改成非增,那么就要求 a[j] <= a[k],所以dp[i][j] = min(dp[i - 1][k] + d) k < j; #include <algorithm> #in

POJ 3666 Making the Grade [DP]

题意: 给定一个序列,以最小代价将其变成单调不增或单调不减序列,这里的代价看题目公式. 思路: 很容易想到是DP. 1. 对前i个序列,构成的最优解其实就是与两个参数有关.一个是这个序列处理后的最大值mx,和这个序列处理的代价值cost. 显然最大值mx最小最好(这样第i+1个值可以不花代价直接接在其后面的可能性更大),cost最小也最好(题意要求),但是两者往往是鱼和熊掌. 用dp[i][j]表示:前i个数构成的序列,这个序列最大值为j,dp[i][j]的值代表相应的cost. 所以状态转移方

【编程题目】请修改 append 函数,利用这个函数实现两个非降序链表的并集

42.请修改 append 函数,利用这个函数实现(链表):两个非降序链表的并集,1->2->3 和 2->3->5 并为 1->2->3->5另外只能输出结果,不能修改两个链表的数据. 感觉网上理解题意略有不同,我理解的题意: 只是输出最后的结果,不用生成一个新的链表,也不修改原有链表. 给的数据非降序就是 1 1 2 2 3 这样可以有重复数字的递增 输出时,不显示重复的数字. 基于这些理解,题目不难,代码如下: /* 42.请修改 append 函数,利用这

[经典面试题]给定一个有序(非降序)数组A,可含有重复元素,求最小的i使得A[i]等于target,不存在则返回-1

[题目] 给定一个有序(非降序)数组A,可含有重复元素,求最小的i使得A[i]等于target,不存在则返回-1. [分析] 此题也就是求target在数组中第一次出现的位置.这里可能会有人想先直接用原始的二分查找,如果不存在直接返回-1, 如果存在,然后再顺序找到这个等于target值区间的最左位置,这样的话,最坏情况下的复杂度就是O(n)了,没有完全发挥出二分查找的优势. 这里的解法具体过程请参考实现代码与注释. [代码] /*********************************

按非降序建立n个元素的线性表

Status CreatAscend(LinkList &L,int n) {  int j; LinkList p,q,s; if(n<=0) return ERROR; InitList(L); printf("请输入%d个元素:\n",n); s=(LinkList)malloc(sizeof(LNode)); // 第一个结点 scanf("%d",&s->data); s->next=NULL; L->next=s;

poj 3666 Making the Grade &amp; zoj 3512 Financial Fraud 左偏树 or dp

//poj 3666 //分析:只是在2005年集训队论文黄源河提到的题目上略微有一点点变化 1 #include"iostream" 2 #include"cstdio" 3 using namespace std; 4 const int maxn = 2100; 5 int v[maxn],l[maxn],r[maxn],d[maxn]; //节点信息 6 int N; 7 int tot,root[maxn],num_now[maxn],num_del[ma

poj 3666 Making the Grade 【dp】

题目链接:http://poj.org/problem?id=3666 题意:使得一个序列变为递增或递减序列的最小代价.代价为题中给的公式. 解法:dp[i][j]表示前i个数,以num[j]为末尾的最小代价. 更新的时候枚举 j 转移状态: for (int i = 2; i <= n; i++) { int t = inf; for (int j = 1; j <= n; j++) { t = min(t,dp[i-1][j]); dp[i][j] = t + abs(a[i] - num

POJ - 3666 Making the Grade(dp+离散化)

Description 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