zoukankan      html  css  js  c++  java
  • 矩形分割

    题目链接:http://noi.openjudge.cn/ch0111/03/

    一个二分的题目,估计是数据类型选择不当,折腾了好多天。所以,以后记得尽管使用long  long类型数据呵呵

    描述

    平面上有一个大矩形,其左下角坐标(0,0),右上角坐标(R,R)。大矩形内部包含一些小矩形,小矩形都平行于坐标轴且互不重叠。所有矩形的顶点都是整点。要求画一根平行于y轴的直线x=k(k是整数) ,使得这些小矩形落在直线左边的面积必须大于等于落在右边的面积,且两边面积之差最小。并且,要使得大矩形在直线左边的的面积尽可能大。注意:若直线穿过一个小矩形,将会把它切成两个部分,分属左右两侧。

    输入

    第一行是整数R,表示大矩形的右上角坐标是(R,R) (1 <= R <= 1,000,000)。
    接下来的一行是整数N,表示一共有N个小矩形(0 < N <= 10000)。
    再接下来有N 行。每行有4个整数,L,T, W 和 H, 表示有一个小矩形的左上角坐标是(L,T),宽度是W,高度是H (0<=L,T <= R, 0<w,h <="R)."

    小矩形不会有位于大矩形之外的部分。

    输出

    输出整数n,表示答案应该是直线 x=n。 如果必要的话,x=R也可以是答案。样例输入

    1000
    2
    1 1 2 1
    5 1 2 1

    样例输出

    5

    我的思路:对解区间[0,R]做二分,查找可能的解。(假设每一次二分计算的中间点是解,然后做验证。然后在寻找更合理的解。)
    注意:long long类型数据要使用%lld输入输出。
    暂时还有一个疑惑,就是末尾的绝对值部分。(这个下面再提)
    AC代码:
     1 #include<stdio.h>
     2 #include<math.h>
     3 struct obj
     4 {
     5     long long left,top,w,h;//左上角横、纵坐标和宽、高值
     6     long long rx;//右下角顶点的横坐标 
     7     long long s;//面积 
     8 };
     9 long long sigema(struct obj a[],int n,int mid)
    10 {
    11     int i;
    12     long long sum1,sum2;
    13     sum1=sum2=0;
    14     for(i=0;i<n;i++)
    15     {
    16         if(a[i].rx<=mid) sum1+=a[i].s; //该矩形属左侧
    17         else if(a[i].left>=mid) sum2+=a[i].s;//属右侧
    18         else
    19         {
    20             sum1+=a[i].h*(mid-a[i].left);
    21             sum2+=a[i].h*(a[i].rx-mid);
    22         }
    23     }
    24     return sum1-sum2;
    25 }
    26 int main()
    27 {
    28     long long r,n,i;
    29     struct obj a[10005];
    30     long long minx,maxx,mid,ans,maxx2;
    31     long long temp,temp1,temp2;
    32     
    33     scanf("%lld%lld",&r,&n);
    34     for(i=0;i<n;i++) 
    35     {
    36         scanf("%lld%lld%lld%lld",&a[i].left,&a[i].top,&a[i].w,&a[i].h);
    37         a[i].s=a[i].w*a[i].h;
    38         a[i].rx=a[i].left+a[i].w;
    39         if(i==0)  maxx2=a[i].rx;
    40         else
    41         {
    42             if(a[i].rx>maxx2) maxx2=a[i].rx;
    43         }
    44     }
    45     minx=0;
    46     maxx=r;
    47     while(minx+1<maxx)//需要二分枚举的答案是整数,所以可以用这个方式结束 
    48     {
    49         mid=(minx+maxx)/2;
    50         temp=sigema(a,n,mid);
    51         if(temp>0) maxx=mid;
    52         else if(temp<=0) minx=mid;
    53     }
    54     
    55     temp1=sigema(a,n,minx);
    56     temp2=sigema(a,n,maxx);
    57     /*if(fabs(temp1)<fabs(temp2)) ans=minx;
    58     else ans=maxx;*/
    59     if( temp1<temp2)
    60     {
    61         if(temp1>=0) ans=minx;
    62         else ans=maxx;
    63     }
    64     else if(temp1>temp2)
    65     {
    66         if(temp2>=0) ans=maxx;
    67         else ans=minx;
    68     }
    69     else ans=maxx;
    70     if(ans==maxx2) ans=r;
    71     printf("%lld
    ",ans);
    72     return 0;
    73 }

    这个题目一直有一个疑惑。最开始的时候题目并未有提到有一个大矩形,题目的要求仅仅是“左边部分小矩形的面积之和不小于右边部分小矩形面积之和”。后来题目做了修改,增加了大矩形的约束。参看了别人的代码,也自己验证过,代码后面的if语句里面的绝对值竟然在修改题目后还可以通过。就是下面的语句:

    if(fabs(temp1)<fabs(temp2)) ans=minx;
    else ans=maxx;
    

      我一直都觉得这个语句只能起到约束题目的第一个条件(小矩形落在直线左边的面积必须大于等于落在右边的面积,且两边面积之差最小),并不能够约束题目的第二个条件(要使得大矩形在直线左边的的面积尽可能大)。因为若是直接取绝对值,不能够保证哪一边的面积比较大,只是能够保证两边的面积差距尽量小。

    所以,我在后面代码里面做了修改,用的是这样的代码:
     1 if( temp1<temp2)
     2     {
     3         if(temp1>=0) ans=minx;
     4         else ans=maxx;
     5     }
     6     else if(temp1>temp2)
     7     {
     8         if(temp2>=0) ans=maxx;
     9         else ans=minx;
    10     }
    11     else ans=maxx;

    另外,还要一个地方比较重要,那就是最后一个if语句。

    1 if(ans==maxx2) ans=r;



  • 相关阅读:
    select 1
    使用Word2016发布CSDN博客
    使用word 2013 发布csdn博客
    使用word写CSDN博客文章
    用Word 写csdn blog
    如何使用office2016发布CSDN博客
    用word发CSDN blog
    使用word文档直接发表博客 8 )
    将Word发布到博客园
    Word 2010发布博客文章(修正)
  • 原文地址:https://www.cnblogs.com/huashanqingzhu/p/5603974.html
Copyright © 2011-2022 走看看