题解:这题就是离散化加BFS就好了。具体过程代码注释里有。
#include <bits/stdc++.h>
#define mem(a, b) memset(a, b, sizeof(a))
#define eps 0.000000000001
#define pi acos(-1)
using namespace std;
int n, mps[3005][3005], numx[3005], numy[3005], w, h, nx, ny, que[3000], ox[4] = {0, 0, 1, -1}, oy[4] = {1, -1, 0, 0};
//线段的个数,离散化后的图,对X坐标的离散化,对Y坐标的离散化,长,宽,x坐标的离散化个数,y坐标的离散化个数,数组模拟的队列,bfs的x变化,bfs的y变化;
bool vis[3005][3005];
//bfs的判重数组;
struct line
{
int x, y, x2, y2;
}li[505];
//结构体,线
//把值存入数组,为离散化做准备
void get(int a, int flag)//对坐标a的离散化,为了保证不影响结果性,需要离散化它自己和它周围的坐标,因为如果不离散化周围的坐标,有可能会出现种种情况
{ //...#..#..
if(!flag) //...#..#..
{ //...#..#..
if(a - 1 >= 1)//保证在给定的范围内 //...#..#..
numx[++nx] = a - 1; //...#..#.. 答案 3
numx[++nx] = a; //对于这么一幅图,离散化它周围的坐标,最后的图是
if(a + 1 <= w) //.#.#.
numx[++nx] = a + 1; //.#.#.
} //.#.#.
else //.#.#.
{ //.#.#. 答案 3
if(a - 1 >= 1) //如果只离散化它自己,它的图是
numy[++ny] = a - 1; //##
numy[++ny] = a; //##
if(a + 1 <= h) //##
numy[++ny] = a + 1; //##
} //## 答案 0
}
int getposx(int a)//对离散化的x进行二分查找,返回它离散化的下标,例如a[5] = {0, 1, 4, 5, 9}; 那么4 返回的就是2;
{
int l = 1, r = nx;
while(l <= r)
{
int mid = (l + r) / 2;
if(numx[mid] < a)
l = mid + 1;
else if(numx[mid] > a)
r = mid - 1;
else
return mid;
}
}
int getposy(int a)//对离散化的y进行二分查找,返回它离散化的下标
{
int l = 1, r = ny;
while(l <= r)
{
int mid = (l + r) / 2;
if(numy[mid] < a)
l = mid + 1;
else if(numy[mid] > a)
r = mid - 1;
else
return mid;
}
}
void bfs(int x, int y)//广搜,搜出每一个联通块,对每个搜到的点进行标记
{
vis[x][y] = 1;
int he = 0, fa = 0;
que[he++] = x;
que[he++] = y;
while(he != fa)
{
x = que[fa++];
y = que[fa++];
fa %= 3000; //对于手打的队列需要取模
for(int i = 0;i < 4;i++)
{
int tmpx = x + ox[i];
int tmpy = y + oy[i];
if(tmpx >= 1&&tmpx <= nx&&tmpy >= 1&&tmpy <= ny&&!mps[tmpx][tmpy]&&!vis[tmpx][tmpy])//判断是否超限和是否是可以走的,还有有没有走过
{
vis[tmpx][tmpy] = 1;
que[he++] = tmpx;
que[he++] = tmpy;
he %= 3000;
}
}
}
}
int main()
{
while(~scanf("%d%d", &w, &h))//输入长宽
{
mem(mps, 0);//初始化
mem(vis, 0);
nx = 0;
ny = 0;
scanf("%d", &n);
for(int i = 1;i <= n;i++)
{
scanf("%d%d%d%d", &li[i].x, &li[i].y, &li[i].x2, &li[i].y2);
get(li[i].x, 0);//为了离散化,先存值
get(li[i].x2, 0);
get(li[i].y, 1);
get(li[i].y2, 1);
}
//下面四步是离散化
sort(numx + 1, numx + 1 + nx);//对x排序,从小到大
sort(numy + 1, numy + 1 + ny);//对y排序,从小到大
nx = unique(numx + 1, numx + 1 + nx) - numx - 1;//对x unique 返回unique的个数,例如a[5] = {0, 1, 1, 1, 2} , unique后是a[5] = {0, 1, 2, 1, 1}, nx值是2;
ny = unique(numy + 1, numy + 1 + ny) - numy - 1;//对y unique 返回unique的个数
for(int i = 1;i <= n;i++)//对离散化后的点,按题意建图
{
if(li[i].x == li[i].x2)
{
int x = getposx(li[i].x);
int y = getposy(li[i].y);
int y2 = getposy(li[i].y2);
if(y > y2)
swap(y, y2);
for(int j = y;j <= y2;j++)
mps[x][j] = 1;
}
else
{
int y = getposy(li[i].y);
int x = getposx(li[i].x);
int x2 = getposx(li[i].x2);
if(x > x2)
swap(x, x2);
for(int j = x;j <= x2;j++)
mps[j][y] = 1;
}
}
int ans = 0;
for(int i = 1;i <= nx;i++)
{
for(int j = 1;j <= ny;j++)
{
if(!vis[i][j]&&!mps[i][j])//对于没标记过的点进行bfs,而每有一个未标记的点,都代表一个联通块
{
bfs(i, j);
ans++;
}
}
}
printf("%d\n", ans);
}
return 0;
}
/*
10 10
5
1 4 6 4
1 8 10 8
4 1 4 10
9 1 9 5
10 6 10 10
*/