zoukankan      html  css  js  c++  java
  • 第七届河南省赛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)
    既然要求中位数,而且数列又是静态数列,可以想到用划分树来求.划分树除了空间比左偏树大一点之外,执行效率和正确率都比左偏树要好。左偏树的常数相对比较大。
     
  • 相关阅读:
    Linkerd 2.10(Step by Step)—将 GitOps 与 Linkerd 和 Argo CD 结合使用
    Linkerd 2.10(Step by Step)—多集群通信
    Linkerd 2.10(Step by Step)—使用 Kustomize 自定义 Linkerd 的配置
    Linkerd 2.10(Step by Step)—控制平面调试端点
    Linkerd 2.10(Step by Step)—配置超时
    Linkerd 2.10(Step by Step)—配置重试
    Linkerd 2.10(Step by Step)—配置代理并发
    本地正常运行,线上环境诡异异常原因集合
    Need to invoke method 'xxx' declared on target class 'yyy', but not found in any interface(s) of the exposed proxy type
    alpine 安装常用命令
  • 原文地址:https://www.cnblogs.com/handsomecui/p/5096654.html
Copyright © 2011-2022 走看看