zoukankan      html  css  js  c++  java
  • [P2769] 猴子上树

    ## 题目描述

    在猴村有一条笔直的山路,这条山路很窄,宽度忽略不计。有 n只猴子正站在山路上静静地观望今天来参加比赛的各位同学。用一个正整数Xi表示第i只猴子所站位置,任意两只猴子的所站位置互不相同。在这条山路的m个位置上种着一些高大的树木,正整数Yj表示第j棵树木所在的位置,任意两棵树的位置互不相同。

    正当猴子们聚精会神的欣赏各位高超编程技能 聚精会神的欣赏各位高超编程技能时,一只老虎大摇摆的走了过来。猴子们吓得直冒冷汗,第一反应就是找棵大树爬上去这样能避免被老虎咬死或者吃掉(不考虑老虎上树问题)。

    在位置a的猴子跑到在位置b的大树上,需要消耗能量为|a-b|(即 a-b的绝对值)。为了尽可能有效利用这些大树避难,每棵上至少要一只猴子。 请编程计算n只猴子全部上树最少需要消耗多能量?

    输入输出格式

    输入格式:

    输入共4行。

    第1行一个整数 n,表示猴子的数量。

    第2行n个整数,i个整数个整数Xi表示第i只猴子所在的位置。

    第3行一个整数m,表示大树的数量。

    第4行m个整数,第j个整数表示第j棵大树所在的位置。

    输出格式:

    输出一行,一个整数表示n只猴子全部上树最少需要消耗的能量。

    输入输出样例

    输入样例#1: 复制

    3
    1 4 5
    2
    3 8

    输出样例#1: 复制

    6

    输入样例#2: 复制

    3
    3 1 10
    2
    8 3

    输出样例#2: 复制

    4

    说明

    30%的数据,(1≤n≤500,1≤X_i,Y_i≤10^5)

    100%的数据,(1≤n≤5000,1≤m≤n,1≤Xi_,Y_i≤10^9)

    Solution

    动态规划+滚动数组优化空间+排序。
    先把猴子和树排序,这很容易想到,贪心肯定不行,因为你无法确定哪些树有猴子,而且保证全局最优,于是想到了DP。
    我们设(f[i][j])代表前(i)只猴子占满了前(j)颗树,容易想到DP方程为

    [f[i][j]=min(f[i-1][j-1]+abs(x[i]-y[j]),f[i-1][j]+mn[i][j]); ]

    (mn[i][j])代表第(i)只猴子在上前(j)颗树的最小能量,可以预处理出来。
    发现(f[i][j]会爆)(int),所以要开(long~long),数据范围5000?,好像
    (f[5000][5000])会爆,容易发现(f[i][j])转移只和上一次有关,可以用滚动数组,于是转移方程为$$f[p][j]=min(f[pxor1][j-1]+abs(x[i]-y[j]),f[pxor1][j]+mn[i][j]);$$
    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    ll f[2][5010],x[10010],y[10010];
    int mn[5010][5010];
    int sba(int x)
    {
        if(x<0) return -x;
        return x;
    }
    int main()
    {
        memset(f,0x3f,sizeof(f));
        ll n,m;
        cin>>n;
        for(ll i=1;i<=n;i++)
        cin>>x[i];
        sort(x+1,x+1+n);
        cin>>m;
        for(ll i=1;i<=m;i++)
        cin>>y[i];
        sort(y+1,y+1+m);
        for(ll i=1;i<=n;i++)
        mn[i][0]=2e9;
        for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
        mn[i][j]=min(mn[i][j-1],sba(x[i]-y[j]));
        f[1][1]=sba(x[1]-y[1]);
        for(ll i=2;i<=n;i++)
        {
            ll qq=min(i,m);
        	for(ll j=1;j<=qq;j++)
        	{
        	    ll p=i%2;
        	    f[p][j]=min(f[p^1][j-1]+sba(x[i]-y[j]),f[p^1][j]+mn[i][j]);
        	}
        }
        ll p=n%2;
        cout<<f[p][m];
    }
    

    博主蒟蒻,可以随意转载,但必须附上原文链接k-z-j

  • 相关阅读:
    c#的逆向工程-IL指令集
    利用nginx concat模块合并js css
    DotNetOpenAuth实践之Webform资源服务器配置
    STL使用迭代器逆向删除
    驱动安装时的错误
    How to detect the presence of the Visual C++ 2010 redistributable package
    Shell脚本使用汇总整理——文件夹及子文件备份脚本
    Shell脚本使用汇总整理
    Shell脚本使用汇总整理——mysql数据库5.7.8以后备份脚本
    Shell脚本使用汇总整理——mysql数据库5.7.8以前备份脚本
  • 原文地址:https://www.cnblogs.com/kzj-pwq/p/9606653.html
Copyright © 2011-2022 走看看