zoukankan      html  css  js  c++  java
  • bzoj 1597 斜率DP

    1597: [Usaco2008 Mar]土地购买

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 5115  Solved: 1897
    [Submit][Status][Discuss]

    Description

    农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000). 每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25. FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

    Input

    * 第1行: 一个数: N

    * 第2..N+1行: 第i+1行包含两个数,分别为第i块土地的长和宽

    Output

    * 第一行: 最小的可行费用.

    Sample Input

    4
    100 1
    15 15
    20 5
    1 100

    输入解释:

    共有4块土地.

    Sample Output

    500

    HINT

    FJ分3组买这些土地: 第一组:100x1, 第二组1x100, 第三组20x5 和 15x15 plot. 每组的价格分别为100,100,300, 总共500.


    首先对决策的有序,对土地按照长 x,宽 y 递增排序。

    如果:

    第一块土地,和第二块土地,第二块土地长宽都要比第一块大,那么第一块就等于不起作用,那么可以不用考虑第一块土地,

    于是删掉所有这种不需要考虑的土地,就成了 x 递增,y 递减排列的土地。

    这时候,对于前面 i 块土地来说,会可以分成很多部分,要成本最少的一种划分。于是——DP思路就来了。

    f[i] 前 i 块土地的最优值。

    那么:

    这样O(n^2) 的算法就呼之欲出了,但是,还是会TLE;

    怎么办呢?


    斜率DP:

    对于 i 点,与之相切的点 斜率才最小,保证 < x[i] ,这个点才是划分点。

    到这里,分析就已经完成了,只差队列维护决策点。这个凸多边形了。

    就是套路了,

    • 考虑凸多边相切的变化规律,找到划分点。
    • 用划分点计算新的值。
    • 新的值更新凸多边形
    #include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    const int maxn = 50010;
    
    struct Node
    {
        ll x,y;
        bool operator < (const Node& rhs) const {
            if(x==rhs.x) return y < rhs.y;
            return x < rhs.x;
        }
    }p[maxn];
    
    ll n,f[maxn],q[maxn];
    
    double slope(long long a,long long b) {
        return (1.0*(f[a]-f[b])/(p[a+1].y-p[b+1].y));
    }
    
    int main(int argc, char const *argv[])
    {
        scanf("%I64d",&n);
    
        for(int i = 1; i <= n; i++)
            scanf("%I64d%I64d",&p[i].x,&p[i].y);
    
        sort(p+1,p+n+1);
    
        int cnt = 0;
        for(int i = 1; i <= n; i++) {
            if(p[i].y<=p[i+1].y) continue;
            while(cnt&&p[cnt].y<=p[i].y) --cnt;
            p[++cnt] = p[i];
        }
    
        int h = 0,t = 1;
        q[h] = 0;
    
    
        for(int i = 1; i <=cnt; i++) {
            while(t-h>1&&slope(q[h],q[h+1])>=-p[i].x) ++h;  //删除队首非最优决策点
    
            f[i] = f[q[h]] + p[q[h]+1].y * p[i].x;
    
            while(t-h>1&&slope(q[t-2],q[t-1])<slope(q[t-1],i)) --t;
            q[t++] = i;
    
    
        }
    
        cout<<f[cnt]<<endl;
        return 0;
    }
    View Code

     参考:http://www.cnblogs.com/akhpl/p/6715148.html

  • 相关阅读:
    WP开发笔记——页面传参
    WP开发笔记——控件倾斜效果
    WP开发笔记——不同Item显示不同ApplicationBar:适用于Pivot与Panorama
    WP开发笔记——WP APP添加页面跳转动画
    WP开发笔记——去除 HTML 标签
    WP开发笔记——字符串 转 MD5 加密
    WP开发笔记——WP7 SDK使用技巧
    sphinx,coreseek安装
    yii2从零开始一,安装
    array_filter函数
  • 原文地址:https://www.cnblogs.com/TreeDream/p/7482257.html
Copyright © 2011-2022 走看看