2018-10-18 08:38:17
P2449 [SDOI2005]矩形
题目描述
现在我们在一个平面上画了n个矩形。每一个矩形的两边都与坐标轴相平行,且矩形定点的坐标均为整数。
现我们定义满足如下性质的图形为一个块:
1.每一个矩形都是一个块;
2.如果两个块有一段公共的部分,那么这两个块就会形成一个新的块,否则这两个块就是不同的。
示例:
图1中的矩形形成了两个不同的块。图2中的矩形形成了一个块。
任务:
请写一个程序:
1.从文本文件PRO.IN中读入各个矩形的顶点坐标;
2.找出这些矩形中不同的块的数目;
3.把结果输出到文本文件PRO.OUT中。
输入输出格式
输入格式:
文本文件PRO.IN的第一行包括一个整数n,1<=n<=7000,为矩形的数目。以下的n行为矩形顶点的坐标。
每一个矩形都是用四个整数来描述的:左下角的x坐标、左下角的y坐标、右上角的x坐标和右上角的y坐标。
所有的坐标都是不大于10000的非负整数。
输出格式:
在文本文件PRO.OUT中输出唯一的一个整数——这些矩形所形成的不同的块的数目。
输入输出样例
输入样例#1:
9
0 3 2 6
4 5 5 7
4 2 6 4
2 0 3 2
5 3 6 4
3 2 5 3
1 4 4 7
0 0 1 4
0 0 4 1
输出样例#1:
2
♦题目大意:
输入n个矩形,若两个矩形重合则将这两个矩形合并在一起,最后问一共有几块区域?
注意:两个矩形边与边重合能合成一块,而两个矩形点与点重合则不行!
♦思路:
显然,一个并查集不就搞定了吗?
可是!这道题的难点并不是并查集本身吧,更多的是怎么判断这两个矩形重合!
一开始,我的思路是将a矩形内的点全部标记一下,再枚举b矩形,看b矩形中有a矩形标记
过的几个点,若点大于1,则表示重合。虽然,这个方法是可行的,但是看数据范围,矩形
的坐标是不大于10000的非负整数,啊,显然就炸掉了!那怎么办呢?我我又很懒,那懒人
有懒方法,嗯,就从反向考虑吧!
如果b矩形的4个点的横坐标都大于a矩形的下点横坐标/都小于a矩形的上点横坐标..(依
旧很懒,如图,红色为a矩形,绿色为b矩形)
这4种情况则是不重合,那么怎么判断只有一个点重合的情况呢?其实只要特判一下就好了!
这样,这道题就AC了!
#include<bits/stdc++.h>
using namespace std;
int n;
struct Squ{int x,y,xx,yy;}squ[7000+10];
int fa[7000+10];
int ans[7000+10],oo;
int fi,fj;
int c;
int jud(int d,int dd)
{
int xf1=squ[d].x,yf1=squ[d].y,xf2=squ[d].xx,yf2=squ[d].yy;
int xl1=squ[dd].x,yl1=squ[dd].y,xl2=squ[dd].xx,yl2=squ[dd].yy;
if((xl1<xf1&&xl2<xf1)||(xl1>xf2&&xl2>xf2)||(yl1<yf1&&yl2<yf1)||(yl1>yf2&&yl2>yf2)) return 0;
if((xl1==xf2&&yl1==yf2)||(xl1==xf2&&yl2==yf1)||(xl2==xf1&&yl1==yf2)||(xl2==xf1&&yl2==yf1)) return 0;
return 1;
}
int find(int x)
{
if(fa[x]==x) return x;
return fa[x]=find(fa[x]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d%d%d",&squ[i].x,&squ[i].y,&squ[i].xx,&squ[i].yy);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=2;i<=n;i++)
for(int j=1;j<=i-1;j++)
{
c=jud(j,i);
if(c==1)
{
fi=find(i);
fj=find(j);
if(fi!=fj) fa[fi]=fj;
}
}
for(int i=1;i<=n;i++)
{
fa[i]=find(i);
ans[fa[i]]++;
}
for(int i=1;i<=n;i++)
if(ans[i]>0) oo++;
//for(int i=1;i<=n;i++)
//printf("%d",fa[i]);
printf("%d",oo);
return 0;
}