zoukankan      html  css  js  c++  java
  • POJ3666 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

    A B 1| + | A B 2| + ... + | 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




    题意:

    给定一个序列,以最小代价将其变成单调不增或单调不减序列,这里的代价看题目公式。

    思路:

    很容易想到是DP。

    1.

    对前i个序列,构成的最优解其实就是与两个参数有关。一个是这个序列处理后的最大值mx,和这个序列处理的代价值cost。

    显然最大值mx最小最好(这样第i+1个值可以不花代价直接接在其后面的可能性更大),cost最小也最好(题意要求),但是两者往往是鱼和熊掌。

    用dp[i][j]表示:前i个数构成的序列,这个序列最大值也就是最后一个值为j,dp[i][j]的值代表相应的cost。

    所以状态转移方程如下:

    dp[i][j]=abs(j-w[i])+min(dp[i-1][k]);(k<=j)


    行为i,j为列

       

    这个表格是根据转移方程写出来的dp数组。

    再仔细看一下转移方程:dp[i][j]=abs(j-w[i])+min(dp[i-1][k]);(k<=j)

    右边没填充的是因为填充的数字肯定比前面的数字大,无用,因为在求min( dp[i-1][k] )时,是求最小值,既然更大,则最小值时无需考虑。

    又从表格中可以看出:

    dp[i][j]=abs(j-w[i])+min(dp[i-1][k]);(k<=j)这里的k无需从1遍历到j。

    只要在对j进行for循环的时候不断更新一个dp[i-1][j]的最小值mn=min(mn,dp[i-1][j]),

    然后对dp[i][j]=abs(j-w[i])+mn即可;

    这样改进之后即可从本来的时候时间复杂度O(NMM)改进为O(NM);


    但是,这里的m是A[i]的最大值,显然TLE。

    所以必须用离散化思想改进,因为N=2000。远小于A[i]的最大值。

    离散化:将序列排序一下,然后用位置的前后关系来制定其值,这样时间复杂度变成O(N^2).


    最后是这题数据有bug,只需要求不减序列即可。

    如下代码是更正之后的,网上多数是有BUG的,后台测试数据太水

    参考网址:here andhere

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #define LL long long int
    #define MAX 2000+5
    using namespace std;
    int n,a[MAX],b[MAX];
    LL dp[MAX][MAX];
    
    LL solve()
    {
    	for(int i=1;i<=n;i++)
    	{
    		LL mn=dp[i-1][1];
    		for(int j=1;j<=n;j++)
    		{
    			mn=min(mn,dp[i-1][j]);
    			dp[i][j]=abs(a[i]-b[j])+mn;
    		}
    	}
    	LL res=dp[n][1];
    	for(int i=1;i<=n;i++)
    		res=min(res,dp[n][i]);
    	return res;
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",a+i);
    		b[i]=a[i];
    	}
    	sort(b+1,b+n+1);
    	LL res1 = solve();
    
    	reverse(b+1,b+n+1);
    	LL res2 = solve();
    	printf("%lld
    ",min(res1,res2));
    
    	return 0;
    }
    



  • 相关阅读:
    转:Windows Phone 7 设计简介
    Windows Phone开发(15):资源
    Windows Phone开发(16):样式和控件模板
    转: kali msfvenom生成木马
    转:Uncovering Drupalgeddon 2(cve-2018-7600)漏洞深度解析(附漏洞利用代码地址)
    转:XSS知识大总结
    转:perl源码审计
    perl相关知识
    python引入模块时import与from ... import的区别
    转:Exploiting Windows 10 in a Local Network with WPAD/PAC and JScript
  • 原文地址:https://www.cnblogs.com/zswbky/p/6792905.html
Copyright © 2011-2022 走看看