题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6665
题目大意:给定四个点分别为两个矩形的左上角和右下角,两个矩形与坐标轴平行,问坐标平面(含负轴,但矩形只在第一象限内,部分边可能在正轴上)被两个矩形划分为几个区域(原意问的是几个连通点集但因为是实数点所以相当于问的是区域)。
思路:如题,离散化。可以看到点坐标的值可能非常大,但是注意求的只是区域个数,而并不用求每个区域内点的个数,所以我们想要的信息只有点和点之间的位置关系,这时候最简单的方法,就是枚举每个点之间的关系,但是这个太累了(没错偷懒才是人类进步的源泉),大致算一下有二十多种,就算有部分情况是重叠的也要全部列先一遍吧,就是很麻烦(确信)。这时候就要用到离散化,如前所言,我们只需要点和点之间的位置关系,那么我们就可以在不改变他们相对随意改变值的大小,也就是说可以把很大的值降到很小的范围内然后。。。然后就可以暴力涂色了。
具体的操作就是,先把所有的x,y值放在一起排序,然后从小到大赋值,我选择的是从零开始赋偶数值,这样避免了某些实数点在涂色时无法涂到导致区域没有被统计的情况(相当于加大了线和线之间的距离),然后重新排序,排成读入的顺序,然后直接给每条边打上标记,然后就可以dfs涂色了。
代码如下:
#include<iostream> #include<cstdio> #include<set> #include<stdio.h> #include<string.h> #include<math.h> #include<vector> #include<stdlib.h> #include<queue> #include<algorithm> #include<map> #include<stack> using namespace std; int co[20][20]; struct node { int v; int id; } e[20]; int cc; bool cmp(node a,node b) { return a.v<b.v; } bool cmpid(node a,node b) { return a.id<b.id; } int chec(int x,int y)//检查是否越界或已经被涂色 { if(x>=20||y>=20||x<0||y<0||co[x][y]!=0) { return 0; } return 1; } int mi[4][2]= {0,-1,0,1,1,0,-1,0}; int dfs(int x,int y,int cc) { co[x][y]=cc; for(int i=0; i<4; i++) { if(chec(x+mi[i][0],y+mi[i][1])) { dfs(x+mi[i][0],y+mi[i][1],cc); } } return 0; } int main() { int t; scanf("%d",&t); while(t--) { memset(co,0,sizeof(co)); for(int i=0; i<8; i++) { scanf("%d",&e[i].v); e[i].id=i; } sort(e,e+8,cmp);//排序后离散化 int k=2; int be=e[0].v; e[0].v=2; for(int i=1; i<8; i++)//离散化的赋值阶段 { if(e[i].v==be) { e[i].v=k; } else { be=e[i].v; k+=2; e[i].v=k; } } sort(e,e+8,cmpid);//排回原序 for(int i=0; i<8; i+=4)//标记线段 { for(int j=e[i].v; j<=e[i+2].v; j++) { co[j][e[i+1].v]=-1; co[j][e[i+3].v]=-1; } for(int j=e[i+1].v; j<=e[i+3].v; j++) { co[e[i].v][j]=-1; co[e[i+2].v][j]=-1; } } cc=0; for(int i=0; i<20; i++)//涂色 { for(int j=0; j<20; j++) { if(co[i][j]==0) { dfs(i,j,++cc); } //printf("%2d ",co[i][j]); } } printf("%d\n",cc); } return 0; }
原文地址:https://www.cnblogs.com/forever3329/p/11367630.html
时间: 2024-09-29 09:47:02