pku1177 Picture(矩形外围总周长)

  这题我先是用离散化做了下,发现可以过,时间当然要久点。在离散化中有这样一个概念:超元线段。这些线段将平面分割成
大小不相当(或相等)的矩形,这些矩形的边要么是给定矩形的边的一部份要么完全和给定矩形无关。我们只有按给定矩形的顶点
的x坐标,y坐标分别画出垂直x轴,y轴的直线,用这些直线来分割平面,它们相交得到的线段就是超元线段。只有统计出超元线段
出现的次数矩形的总周长就可以算到了。
  1. /*pku1177
  2.   Name: Picture
  3.   Date: 29-07-08 13:52
  4.   Description: 计算几何,离散化后求周长 
  5. */
  6. #include<stdio.h>
  7. #include<algorithm>
  8. #define pr printf
  9. int x[10002],y[10002];
  10. int a[5002][4];
  11. int  A[10002],n;
  12. int cmp(const void * a,const void *b)
  13. {
  14.     return *(int *)a-*(int * )b;    
  15. }
  16. int search_bin(int *t,int k,int start,int end)
  17. {
  18.        int low=start,high=end-1,mid;
  19.        while (low<=high)
  20.            {
  21.              mid=(low+high)/2;
  22.              if (k==t[mid]) return mid;
  23.                  else if (k<t[mid]) high=mid-1;
  24.                 else low=mid+1;
  25.            }
  26.         return -1;
  27. }
  28. void count_x(int index){
  29.     int i,x1=x[index],x2=x[index+1];
  30.     int y1,y2;
  31.     for(i=0;i<n;i++)
  32.         if(a[i][0]<=x1 && a[i][2]>=x2){//这个矩形跨越了该原线段 
  33.                 
  34.                 A[y1=search_bin(y,a[i][3],0,2*n)]++; 
  35.                 A[y2=search_bin(y,a[i][1],0,2*n)]--;
  36.             }
  37.     }
  38. void count_y(int index){
  39.     int i,y1=y[index],y2=y[index+1];
  40.     for(i=0;i<n;i++)
  41.         if(a[i][1]<=y1 && a[i][3]>=y2){//这个矩形跨越了该原线段 
  42.                 A[search_bin(x,a[i][2],0,2*n)]++; 
  43.                 A[search_bin(x,a[i][0],0,2*n)]--;
  44.             }
  45.     }
  46. int add(){//该超元线段出现次数 
  47.     int i,sum,ad;
  48.     sum=0;ad=0;
  49.     for(i=0;i<2*n;i++)
  50.         {
  51.             if(A[i]!=0)
  52.             {
  53.                if(ad==0)sum++;
  54.                  ad+=A[i];
  55.               if(ad==0)sum++;
  56.             }    
  57.            
  58.         }
  59.      return sum; 
  60. }
  61. int main(){
  62.     int i,j,k,v1,v2,h2,h1;
  63.     scanf("%d",&n);
  64.     for(i=0,k=0;i<n;i++,k++)
  65.     {
  66.         scanf("%d%d%d%d",&a[i][0],&a[i][1],&a[i][2],&a[i][3]);    
  67.         x[k]=a[i][0],y[k]=a[i][1],x[++k]=a[i][2],y[k]=a[i][3];
  68.     }
  69.     qsort(x,2*n,sizeof(int),cmp);
  70.     qsort(y,2*n,sizeof(int),cmp); 
  71.     int ans=0,len,tmp;
  72.     for(i=0;i<2*n-1;i++)//横线的超元线段 
  73.     {
  74.         len=x[i+1]-x[i];
  75.         if(len==0)continue;
  76.         for(j=0;j<2*n;j++)A[j]=0;
  77.         count_x(i);
  78.         tmp=add();
  79.         ans+=(tmp*len);
  80.     }
  81.     for(i=0;i<2*n-1;i++)//竖线的超元线段
  82.     {
  83.         for(j=0;j<2*n;j++)A[j]=0;
  84.         len=y[i+1]-y[i];
  85.         if(len==0)continue;
  86.         count_y(i);
  87.           tmp=add();
  88.         ans+=(tmp*len);
  89.     } 
  90.             pr("%d/n",ans);
  91. /*
  92. 2
  93. 4 2 10 9
  94. 6 5 15 13
  95. 44
  96. 3
  97. -15 0 5 10
  98. -5 8 20 25
  99. 15 -4 24 14
  100. */

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值