区域个数 坐标离散化 BFS算法

题解:这题就是离散化加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 
*/  


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值