hdu3669 Cross the Wall

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)
Total Submission(s): 4619    Accepted Submission(s): 846


Problem Description
“Across the Great Wall, we can reach every corner in the world!” Now the citizens of Rectland want to cross the Great Wall. 
The Great Wall is a huge wall with infinite width and height, so the only way to cross is to dig holes in it. All people in Rectland can be considered as rectangles with varying width and height, and they can only dig rectangle holes in the wall. A person can pass through a hole, if and only if the person’s width and height is no more than the hole’s width and height both. To dig a hole with width W and height H, the people should pay W * H dollars. Please note that it is only permitted to dig at most K holes for security consideration, and different holes cannot overlap each other in the Great Wall. Remember when they pass through the wall, they must have their feet landed on the ground.
Given all the persons’ width and height, you are requested to find out the minimum cost for digging holes to make all the persons pass through the wall.
 

Input
There are several test cases. The first line of each case contains two numbers, N (1 <= N <= 50000) and K (1 <= K <= 100), indicating the number of people and the maximum holes allowed to dig. Then N lines followed, each contains two integers wi and hi (1 <= wi, hi <= 1000000), indicating the width and height of each person.
 

Output
Output one line for each test case, indicates the minimum cost.

 

Sample Input
2 1 1 100 100 1 2 2 1 100 100 1
 

Sample Output
10000 200

这题如果用普通的区间dp会超时,要用斜率优化。先使这些矩形按宽从大到小排序,如果宽相同就按高度从高到低排序,然后从第一个开始依次把矩形加入集合,如果当前访问的矩形的高度比最后加入集合的矩形的高度小,那么最后加入集合的矩形一定能够覆盖当前访问的,这样这个矩形就可以跳过不加入集合。注意,最后进行dp的矩形一定要满足宽度递增而高度递减。然后就可以进行dp,用dp[i][j]表示前i个数分成j组所用的最小面积,那么dp[i][j]=min(dp[k][j-1]+a[k+1].h*a[i].w)(j-1<=k<i).设k1<k2且k2比k1优,那么dp[k2][j-1]+w[i]*h[k2+1]<=dp[k1][j-1]+w[i]*h[k1+1],则(dp[k2][j-1]-dp[k1][j-1])/(h[k1+1]-h[k2+1)<=w[i],这里有个注意的地方,因为分母是含k1的项减去含k2的项,所以我们要转化一下,令x=-(h[k+1],那么

分母就变为x2-x1了,又因为随着i的递增,w[i]增加,所以如果满足这个斜率不等式,k2一定是比k1优的,所以可以删除k1.


#include<iostream>
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 999999999999999999
#define maxn 50006
ll dp[maxn][106];
int s[maxn][106];
struct node{
    ll w,h;
}a1[maxn],a[maxn];

bool cmp(node a,node b){
    if(a.w==b.w)return a.h>b.h;
    return a.w>b.w;
}
int q[111111],j;

ll getup(int k){
    return dp[k][j-1];
}
ll getdown(int k){
    return -a[k+1].h;
}


int main()
{
    int n,m,i,tot,k,front,rear;
    ll ans;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++){
            scanf("%lld%lld",&a1[i].w,&a1[i].h);
        }
        sort(a1+1,a1+1+n,cmp);
        tot=1;a[1].w=a1[1].w;a[1].h=a1[1].h;
        for(i=2;i<=n;i++){
            if(a1[i].h<=a[tot].h)continue;
            tot++;
            a[tot].w=a1[i].w;a[tot].h=a1[i].h;
        }
        reverse(a+1,a+1+tot);
        for(i=1;i<=tot;i++){
            dp[i][1]=a[i].w*a[1].h;
        }


        for(j=2;j<=m;j++){
            front=rear=0;
            q[rear]=j-1;
            for(i=j;i<=tot;i++){
                while(front<rear &&  getup(q[front+1])-getup(q[front])<=a[i].w*(getdown(q[front+1])-getdown(q[front]))          ){
                    front++;
                }
                k=q[front];
                dp[i][j]=dp[k][j-1]+a[k+1].h*a[i].w;
                while(front<rear &&  (getup(q[rear])-getup(q[rear-1]))*(getdown(i)-getdown(q[rear]))>=(getup(i)-getup(q[rear]) )*(getdown(q[rear])-getdown(q[rear-1]))                ){
                    rear--;
                }
                rear++;
                q[rear]=i;
            }
        }
        ans=inf;
        for(j=1;j<=m;j++){
            ans=min(ans,dp[tot][j]);
        }
        printf("%lld
",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/herumw/p/9464653.html