区域的个数 (坐标离散化)

来源  :挑战程序设计

题目:w*h的格子上画了n条垂直或水平的宽度为1的直线。求出这些线将格子划分成了多少个区域。

1<=w,h<=1000000.     1<=n<=500

思路:首先,一般会想到直接进行dfs或bfs,但w,h过大,无法直接搜索。坐标离散化的思想就是把有用的坐标提取出来,再建一个坐标系,把这些坐标按照顺序放在这个坐标系中。本题只需存储直线的x,y坐标和直线前后的。所以大小6n*6n就够了。




坐标离散化前后图


#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#include<queue>  
#include<vector>  
#include<cmath>  
#define ll __int64  
#define INF 0x3fffffff  
#define MAXN 505  
using namespace std; 
int w,h,n;  
int dir[4][2]={{-1,0},{0,-1},{0,1},{1,0}};  
int x1[MAXN],x2[MAXN],Y1[MAXN],y2[MAXN];  
bool fld[MAXN*6][MAXN*6];//填充用  
struct Point  
{  
    int x,y;  
    Point(int x_=0,int y_=0):x(x_),y(y_){}  
}point[MAXN*MAXN*6*6];  
  
int compress(int *x1,int *x2,int w)  
{  
    vector<int>xs;  
    for(int i=0;i<n;i++){  
        for(int d=-1;d<=1;d++){ //与它相邻的以及它本身  
            int tx1=x1[i]+d,tx2=x2[i]+d;  
            if(tx1>=1&&tx1<=w) xs.push_back(tx1);  
            if(tx2>=1&&tx2<=w) xs.push_back(tx2);  
        }  
    }  
    sort(xs.begin(),xs.end());//有重复的,排序  
    xs.erase(unique(xs.begin(),xs.end()),xs.end());  
    for(int i=0;i<n;i++){  
        x1[i]=find(xs.begin(),xs.end(),x1[i])-xs.begin();//离散化后的坐标  
        x2[i]=find(xs.begin(),xs.end(),x2[i])-xs.begin();  
    }  
    return xs.size();  
}  
  
void solve()  
{  
    w=compress(x1,x2,w);  
    h=compress(Y1,y2,h);  
    //填充有直线的方块  
    memset(fld,false,sizeof(fld));  
    for(int i=0;i<n;i++){  
        for(int y=Y1[i];y<=y2[i];y++)
		{  
            for(int x=x1[i];x<=x2[i];x++)
			{  
                fld[x][y]=true;  
            }  
        }  
    }  
    //求区域的个数  
    int ans=0;  
    for(int x=0;x<w;x++){  
        for(int y=0;y<h;y++){  
            if(fld[x][y]){  
               continue;  
            }  
            ans++;  
            queue<Point>q;  
            Point p;  
            p.x=x;p.y=y;  
            q.push(p);  
            while(!q.empty()){  
                int sx=q.front().x;  
                int sy=q.front().y;  
                q.pop();  
                for(int i=0;i<4;i++){  
                    int xx=sx+dir[i][0];  
                    int yy=sy+dir[i][1];  
                    if(fld[xx][yy]||xx<0||xx>=w||yy<0||yy>=h) continue;  
                    q.push(Point(xx,yy));  
                    fld[xx][yy]=true;  
                }  
            }  
        }  
    }  
    cout<<ans<<endl;  
}  
  
int main()  
{  
    
    cin>>w>>h>>n;  
    for(int i=0;i<n;i++){  
        cin>>x1[i];  
    }  
    for(int i=0;i<n;i++){  
        cin>>x2[i];  
    }  
    for(int i=0;i<n;i++){  
        cin>>Y1[i];  
    }  
    for(int i=0;i<n;i++){  
        cin>>y2[i];  
    }  
    solve();  
    return 0;  
} 

样例
输入
w=10 h=10 n=5
x1={1,1,4,9,10}
x2={6,10,4,9,10}
y1={4,8,1,1,6}
y2={4,8,10,5,10}
输出 
6




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值