1. 程式人生 > >bzoj 1597 斜率DP

bzoj 1597 斜率DP

hid span click 擴大 page idt sample play bbs

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

bzoj 1597 斜率DP