图形

来源:互联网 发布:mac 设置成代理服务器 编辑:程序博客网 时间:2024/05/16 01:54

一些矩形的海报、照片或其他同样形状的图片被张贴在墙上。它们的边都是垂直或水平的。每个矩形可以部分或全部覆盖其它矩形。所有矩形组成的集合的边界称为周界。
写一个程序计算周界。

输入格式:

文件PICTURE.IN 的第一行张贴在墙壁上的矩形图片的数目。在随后的行中,每行有两个点的坐标,分别为某一个矩形的左下角和右上角的坐标。每一个坐标由X坐标与Y坐标组成。

输出格式:

文件PICTURE.OUT包含一行,为一个非负整数,表示输入数据中所有矩形集的周界。

样例输入:

7-15 0 5 10-5 8 20 2515 -4 24 140 -6 16 42 15 10 2230 10 36 2034 0 40 16

样例输出:

228

数据范围:

0 < 矩形数 < 50000

所有坐标在 [-10000,10000]内,结果的值可能需要32位有带符号表示。

时间限制:

1s

空间限制:

256m

题解在代码内

#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
const int size=20005;
const int zero=10000;
struct node{int x,y,f;bool ok;}a[2][maxn*2];
int level[size];
int n,i,x1,x2,y1,y2,ans;
bool cmp(node c,node d){return c.f<d.f||c.f==d.f&&c.ok;}
void find(int o)
{
//我们把矩形的坐标先离散。以处理横条为例。------->>>>>>
 
//①我们在离散每一条横条时记录它们的纵坐标, 同时记录这一横条是矩形的下边(始边)还是上边(终边)。 然后把它们按纵坐标从小到大排好。
 
//②从小到大循环每一个横条。如果是始边,那么把它代表的区间每个格子都加1,否则减1(当然这样效率有点低,最好要用线段树优化)。如果某个格子是始边且原先是0,那么我们就把ans++。 如果某个格子是终边且原先是1,那么我们也把ans++。(具体原理纸上推推就行了)
  sort(a[o]+1,a[o]+n+1,cmp);
  memset(level,0,sizeof(level));
  int j;
  for (int i=1;i<=n;i++)
  {
    if (a[o][i].ok)
    {
      for (j=a[o][i].x;j<a[o][i].y;j++)
      {
        level[j]++;
        if (level[j]==1) ans++;
      }
    }
    else
    {
      for (j=a[o][i].x;j<a[o][i].y;j++)
      {
        level[j]--;
        if (level[j]==0) ans++;
      }
    }
  }
}
int main()
{
 
  scanf("%d",&n);
  for (i=1;i<=n;i++)
  {
    scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
    x1+=zero;x2+=zero;y1+=zero;y2+=zero;//将坐标都加至零及以上
    a[0][i*2-1].x=x1;a[0][i*2-1].y=x2;a[0][i*2-1].ok=true;a[0][i*2-1].f=y1;//OK=1 表示是终边,终边:右边或上面的边
    a[0][i*2].x=x1;a[0][i*2].y=x2;a[0][i*2].ok=false;a[0][i*2].f=y2;//a[0]表示横,1表示纵
    a[1][i*2-1].x=y1;a[1][i*2-1].y=y2;a[1][i*2-1].ok=true;a[1][i*2-1].f=x1;
    a[1][i*2].x=y1;a[1][i*2].y=y2;a[1][i*2].ok=false;a[1][i*2].f=x2;
  }
  n=n*2;
  find(0);
  find(1);
  printf("%d\n",ans);
  return 0;
}

0 0
原创粉丝点击