hdu 3669 Cross the Wall

          Cross the Wall

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

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
 
Source
 
Recommend
lcy
 
挺好的DP斜率优化,个人感觉这道题目是借鉴的usaco 土地购买。
言归正传。。。
首先,第一点要知道的是dp[i][j]=min(dp[i-1][k]+max_W[k+1,i]*max_H[k+1,i])   (i<=k<=j)
1>有序化。。按w或h都行。
2>删点即保证w或h的单调性,当然这道题目都保证了。
  若按w由小到大排序,那么可以有i<j即(w[i]<w[j])且我h[i]<h[j],那么i点是没有必要的,因为它完全可以放在j里面。
  这样就得到了一个w由小到大,h由大到小的点集;
3>然后状态方程就变成了dp[i][j]=min(dp[i-1][k]+w[j]*h[k+1]) (i<=k<=j)
4>斜率优化。。。
  得到方程G=ax+y  => y=-ax+G; 由求G最小知为决策下凸。
维护一个凸包和枚举状态即可。
时间复杂度O(n) 700+ms过的。 当然滚动数组肯定可以, 另外四边形优化可以过,貌似更快。。
 
 1 #include <stdio.h>
 2 #include <algorithm>
 3 #define LL long long
 4 #define MAXN 50010
 5 using namespace std;
 6 int n,m;
 7 LL f[110][MAXN];
 8 struct Node{
 9     int w,h;
10 }a[MAXN],temp;
11 struct Q{
12     LL x,y;
13 }que[MAXN],tempque;
14 int cmp(Node i,Node j)
15 {
16     if(i.w==j.w)    return i.h>j.h;
17     return i.w>j.w;
18 }
19 int main()
20 {
21     int i,j,p,head,tail;
22 
23     while(scanf("%d%d",&n,&m)!=EOF)
24     {
25         for(i=1;i<=n;i++)
26         scanf("%d%d",&a[i].w,&a[i].h);
27 
28         sort(a+1,a+n+1,cmp);
29 
30         p=1;
31 
32         for(i=1;i<=n;i++)
33             if(a[p].h<a[i].h)
34                a[++p]=a[i];
35         n=p;
36         for(i=1;i<=n/2;i++)
37           temp=a[i],a[i]=a[n-i+1],a[n-i+1]=temp;//得到w由小到大,h由大到小
38 
39         for(i=1;i<=n;i++)
40             f[1][i]=(LL)a[1].h*(LL)a[i].w;//初始化
41 
42         for(i=2;i<=m;i++)
43         {
44             head=tail=0;
45             que[tail].x=a[i].h,que[tail++].y=f[i-1][i-1];//队列初始化。。
46             for(j=i;j<=n;j++)
47             {
48                 while(head+1<tail&&a[j].w*que[head].x+que[head].y>a[j].w*que[head+1].x+que[head+1].y)//枚举最优决策
49                             head++;
50 
51                 f[i][j]=(LL)a[j].w*(LL)que[head].x+(LL)que[head].y;
52 
53                 tempque.x=a[j+1].h,tempque.y=f[i-1][j];
54                 while(head+1<tail)
55                         if(((LL)(que[tail-1].x-que[tail-2].x)*(tempque.y-que[tail-1].y)-(LL)(tempque.x-que[tail-1].x)*(que[tail-1].y-que[tail-2].y))>=0)
56                                                     tail--;    //维护凸包
57                         else break;
58                 que[tail++]=tempque;
59             }
60         }
61         LL ans=f[1][n];
62         for(i=1;i<=m;i++)
63           if(ans>f[i][n])ans=f[i][n];
64 
65         printf("%I64d\n",ans);
66     }
67     return 0;
68 }

 

 

 

posted on 2012-04-18 16:46  sleeper_qp  阅读(852)  评论(0编辑  收藏  举报

导航