zoukankan      html  css  js  c++  java
  • 【Usaco2008 Mar】土地购买

    【题目描述】

    农夫John准备扩大他的农场,他正在考虑N (1 <= N <= 50,000) 块长方形的土地. 每块土地的长宽满足(1 <= 宽 <= 1,000,000; 1 <= 长 <= 1,000,000).

    每块土地的价格是它的面积,但FJ可以同时购买多快土地. 这些土地的价格是它们最大的长乘以它们最大的宽, 但是土地的长宽不能交换. 如果FJ买一块3x5的地和一块5x3的地,则他需要付5x5=25.

    FJ希望买下所有的土地,但是他发现分组来买这些土地可以节省经费. 他需要你帮助他找到最小的经费.

    【输入格式】

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

    【输出格式】

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

    【分析】

    这是一道动态规划的题目,设长宽分别为l与w。

    首先,我们进行预处理,将矩阵按照l递减(主关键字),w递增(次关键字)的顺序排序,

    很容易看到的是,如果有两个矩阵i和j,满足l[j]>l[i]并且w[j]>w[i],那么这个矩阵可以完全删除掉,因为在买这个大矩阵j的同时可以把i也顺带买了,这样可以保证排序是唯一确定的。

    接下来,设f(i)为前i个矩阵所需要的最小花费,得到朴素递推方程:

    f[i]=min{f[j]+l[j+1]*w[i]}(j<i)

    复杂度是O(n^2),显然会超时。

    考虑斜率优化:

    现在有两个决策f[j]与f[k],其中j<k。

      假设f[i]从f[j]转移过来比从f[k]转移过来要更优,即:

    f[j]+l[j+1]*w[i]<f[k]+l[k+1]*w[i]

    两边移一下,得到:

    W[i]<(f[k]-f[j])/(l[j+1]-l[k+1])

    为了方便,我们不妨将l数组往前提一位(即l[i]=l[i+1]),

    g[j,k] = (f[k]-f[j])/(l[j] - l[k])

    则如果g[j,k] > w[i] 表示j比k更优。则k可以舍弃掉。

    进而我们发现,当c < b < a < i时,如果有g[c, b] > g[b, a],那么b永远都不会成为计算f[i]时的决策点,为什么呢?
    证明:
    如果g[c, b] > g[b, a],那么我们可以分两个方面考虑g[c, b]与的关系:
      (1)如果g[c, b] > =y[i],那么决策c不会比决策b差,也就说决策b不可能是决策点
      (2)如果g[c, b] < y[i],那么由于g[c, b] > g[b, a],那么g[b, a] < y[i],那么决策a要比决策b好,所以b也不能作为决策点。

    我们用一个队列来实现上面的规则,使得时间复杂度下降。   

      我们现在在满足以上性质的一个队列Q中插入一个新的矩阵i.

    1、我们要判断第一个条件,得到:

    w[i]*(l[Q[front]]-l[Q[front+1]])>(f[Q[front+1]]-f[Q[front]])

    如果成立,说明上面的公式说明的是g[front,front+1]<w[i],即front+1要优于front,所以把front踢出队列,直到不可以再踢进行状态的转移。

    2、我们要判断第二个条件,得到:

    (l[Q[rear]]-l[i])*(f[Q[rear]]-f[Q[rear-1]])>(l[Q[rear-1]]-l[Q[rear]])*(f[i]-f[Q[rear]])

    说明的是对于i,rear,rear-1三个元素来说,有g[rear-1,rear]<g[rear,i],显然,把rear踢出队列,直到不可以再踢时在队尾插入i。

    显然对于每个元素来说,都要一次插入与一次弹出,所以复杂度为O(n)。

     1 #include <cstdlib>
     2 #include <iostream>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <cmath>
     6 #include <algorithm>
     7 const int maxn=50010;
     8 const int INF=0x7fffffff;
     9 using namespace std;
    10 struct matrix
    11 {
    12        long long l,w;//长与宽
    13        //重载运算符 
    14        bool operator <(const matrix &b)const
    15        {
    16             if (l==b.l) return b.w<w;
    17             return b.l<l;
    18        }
    19 }data[maxn];
    20 long long l[maxn],w[maxn],f[maxn];
    21 int Q[maxn];//Q代表队列 
    22 
    23 int main()
    24 {
    25     int i,j,n,cnt=0;
    26     memset(l,0,sizeof(l));
    27     memset(w,0,sizeof(w));
    28     memset(f,0,sizeof(f));
    29     
    30     scanf("%d",&n);
    31     for (i=1;i<=n;i++) scanf("%lld%lld",&data[i].l,&data[i].w);
    32     sort(data+1,data+1+n);//长度递减 
    33     for (i=1;i<=n;i++)
    34     //代表高度需要递增 
    35     if (cnt==0 || data[i].w>w[cnt])
    36     {
    37         cnt++;
    38         w[cnt]=data[i].w;
    39         l[cnt]=data[i].l;       
    40     }
    41     for(i=0;i<cnt;i++)  l[i]=l[i+1];//千万要注意! 
    42 
    43     int front=1,rear=1;
    44     Q[1]=0;
    45     for (i=1;i<=cnt;i++)
    46     {
    47         while (front<rear && w[i]*(l[Q[front]]-l[Q[front+1]])>(f[Q[front+1]]-f[Q[front]]))
    48         front++;
    49         f[i]=f[Q[front]]+l[Q[front]]*w[i];
    50         while (front<rear && (l[Q[rear]]-l[i])*(f[Q[rear]]-f[Q[rear-1]])>(l[Q[rear-1]]-l[Q[rear]])*(f[i]-f[Q[rear]]))
    51         rear--;
    52         Q[++rear]=i;
    53     }
    54     
    55     printf("%lld
    ",f[cnt]);
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    SpringMVC中web.xml中url配置路径 / 和 /* 的区别
    spring mvc @RequestMapping method 不写的话,默认GET、POST都支持,根据前端方式自动适应
    MyBatis项目所引用的一切依赖jar包和自定义设置
    Python 代码性能优化技巧
    linux basic commands
    linuxx virutal machine installation
    安装 Django
    virtualenv (isolated virtual environment) for python runtime
    夜间模式的开启与关闭,父模板的制作
    完成登录与注册页面的前端
  • 原文地址:https://www.cnblogs.com/hoskey/p/3731110.html
Copyright © 2011-2022 走看看