• 第七届河南省赛10403: D.山区修路(dp)


    10403: D.山区修路

    Time Limit: 2 Sec  Memory Limit: 128 MB Submit: 69  Solved: 23 [Submit][Status][Web Board]

    Description

    某山区的孩子们上学必须经过一条凹凸不平的土路,每当下雨天,孩子们非常艰难。现在村里走出来的Dr. Kong决定募捐资金重新修建着条路。由于资金有限,为了降低成本,对修好后的路面高度只能做到单调上升或单调下降。

    为了便于修路,我们将整个土路分成了N段,每段路面的高度分别A1A2,….,An由于将每一段路垫高或挖低一个单位的花费成本相同,修路的总费用与路面的高低成正比。

    现在Dr. Kong希望找到一个恰好含N个元素的不上升或不下降序列B1B2,….,Bn,作为修过的路路段的高度。要求:

     

             | A1-B1| + | A2B2| + ... + | An-Bn|------>最小

    Input

    第一行: K                            表示有多少组测试数据。

    接下来对每组测试数据:

    1:       N                表示整个土路分成了N

    2~N+1行: A1  A2 ……AN     表示每段路面的高度

    2k10      0Ai10    0N500    (i=1,…, N)

    所有数据都是整数。 数据之间有一个空格。

    数据保证| A1-B1|+| A2-B2|+ ... +| An-Bn|的最小值不会超过109

    Output

    对于每组测试数据,输出占一行:| A1-B1|+| A2-B2|+ ... +| An-Bn|的最小值。

    Sample Input

    2
    7
    1 3 2 4 5 3 9
    5
    8 6 5 6 2

    Sample Output

    3
    1

    HINT

     

    Source

    第七届河南省赛

    题解:把一串序列变为一段连续不增,或者连续不减的最小花费;

    dp思想;dp[i][j]代表第i个元素换为第j个值的最小花费;

    可列出状态转移方程:dp[i][j]=abs(m[i]-n[j])+mn;mn为转化为1~j间的最小花费;

    由于是单调递增或者单调递减,只需要升序降序下n数组就可以了,对了,n数组是离散化后的数组;单增或者单减;

    代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define mem(x,y) memset(x,y,sizeof(x))
    #define SI(x) scanf("%d",&x)
    #define SL(x) scanf("%lld",&x)
    #define  PI(x) printf("%d",x)
    #define  PL(x) printf("%lld",x)
    #define P_ printf(" ")
    const int INF=0x3f3f3f3f;
    const double PI=acos(-1.0);
    typedef long long LL;
    const int MAXN=510;
    int m[MAXN],n[MAXN];
    int dp[MAXN][MAXN];
    int N;
    int cmp(int a,int b){
    	return a>b;
    }
    int solve(){
    	int mn;
    	for(int j=1;j<=N;j++)dp[1][j]=abs(m[1]-n[j]);
    	for(int i=2;i<=N;i++){
    		mn=INF;
    		for(int j=1;j<=N;j++){
    			mn=min(mn,dp[i-1][j]);
    			dp[i][j]=abs(m[i]-n[j])+mn;
    		}
    	}
    	int ans=INF;
    	for(int i=1;i<=N;i++){
    		ans=min(ans,dp[N][i]);
    	}
    	return ans;
    }
    int main(){
    	int T;
    	SI(T);
    	while(T--){
    		SI(N);
    		for(int i=1;i<=N;i++)SI(m[i]),n[i]=m[i];
    		int ans1,ans2;
    		sort(n+1,n+N+1);
    		ans1=solve();
    		sort(n+1,n+N+1,cmp);
    		ans2=solve();
    		printf("%d
    ",min(ans1,ans2));
    	}
    	return 0;
    }
    

     有大神用左偏树,划分树写的。。。。

    链接:http://blog.163.com/hacker_james/blog/static/659024432011711105241183/

    人家的思路:

    2.左偏树(leftist) O(nlogn)
    左偏树作为一种可并堆在这里可以起到作用
    我们将每来一个点,把它单独建一棵左偏树,然后跟前一区间的左偏树中的所存的中位数比较,若小于,则和前一区间的左偏树合并,知道比前一区间所记录的中位数是小于或等于当前区间的中位数。
    怎样用左偏树记录中位数? 很简单,每棵左偏树只保存(n+1)/2 个元素,则树顶所保存的最大值即为中位数
     
    注意的是,用左偏树来求中位数在某些情况下是错误的。按照HYH大神的做法,假设现在对于两个序列 4 5 6 7 8 9 和 1 2 3,合并后其中位数是5。然而,按照左偏树只存(n+1)/2 个元素的方法,前者只保留 4 5 6, 后者保留 1 2,两者合并后保留5个元素,所得到的中位数却是6..
    但这道题却没影响,至于为什么? 没想明白.....
     
    3.划分树 
    O(nlogn)
    既然要求中位数,而且数列又是静态数列,可以想到用划分树来求.划分树除了空间比左偏树大一点之外,执行效率和正确率都比左偏树要好。左偏树的常数相对比较大。
     
  • 相关阅读:
    兼容ie和火狐firefox的js调用flash播放器代码特效
    在b/s开发中经常用到的javaScript技术整理
    用javascript+PHP随机显示图片
    1730 博弈
    1198 并查集
    Debug sharepoint
    get your current password on sharepoint(Basci Authentication )
    Site mail box
    Ews get data from exchange shared calender
    upgrade sharepoint 2007 to 2010,2010 to 2013
  • 原文地址:https://www.cnblogs.com/handsomecui/p/5096654.html
Copyright © 2020-2023  润新知