《挑战程序设计竞赛》 坐标离散化技巧实现

问题:

w*h的格子上画了n条或垂直或水平的宽度为1的直线。求出这些线将格子划分了多少个区域 。w和h的范围都为[1, 1000000],n的范围为[1,500]。

输入:

w,h,n

x1,x2,y1,y1

10 10 5
1 9 4 1 10
6 9 4 10 10
4 1 1 8 6
4 5 10 8 10

结果:

6

分析:

w和h都较大,直接搜索肯定超时。因此对图形进行离散化缩减。

自己想的是用set,然而年轻了。set不能进行迭代器算术运算,用set不容易计算新坐标。

能进行算术运算的迭代器只有随机访问迭代器vector,string,deque,要求容器元素存储在连续内存空间里。

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <stack>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <bitset>
#include <list>
#include <sstream>
#include <set>
#include <functional>
using namespace std;

#define maxn 500
int N,W,H;
int X1[maxn],X2[maxn],Y1[maxn],Y2[maxn];
bool alt[maxn*6][maxn*6];
int dx[4] = {0,0,1,-1},dy[4] = {1,-1,0,0};

int compress(int *x1,int *x2,int w)
{
	//把n条线附近用到的坐标加入set
	vector <int> s;
	for (int i = 0; i < N; ++i){
		for (int j = -1; j<= 1; ++j){
			int nx1 = x1[i]+j;
			int nx2 = x2[i]+j;
			if(nx1>=1 && nx1<=w) s.push_back(nx1);
			if(nx2>=1 && nx2<=w) s.push_back(nx2);
		}
	}
	//对数据进行清洗
	sort(s.begin(),s.end());
	s.erase(unique(s.begin(),s.end()),s.end());
	//根据新的宽度,形成新的图,根据原坐标计算新的坐标。
	for (int i = 0; i < N; ++i)
	{
		x1[i] = find(s.begin(),s.end(),x1[i])-s.begin();//新的坐标
		x2[i] = find(s.begin(),s.end(),x2[i])-s.begin();//新的坐标
	}
	return s.size();
}

void solve()
{
	//宽度高度坐标离散化,只截取有用的行和列
	W = compress(X1,X2,W);
	H = compress(Y1,Y2,H);
	//n条线标记
	memset(alt,0,sizeof(alt));
	for (int i = 0; i < N; ++i){
		for (int j = Y1[i]; j <= Y2[i]; ++j){
			for (int k = X1[i]; k <= X2[i]; ++k){
				alt[j][k] = true;
			}
		}
	}
				
	//宽度优先搜索
	queue<pair<int,int>>qu;
	int ans = 0;
	for (int i = 0; i < W; ++i){
		for (int j = 0; j < H; ++j){
			if(alt[i][j]) continue;
			ans++;
			qu.push(make_pair(i,j));
			while(!qu.empty()) {
			    pair <int,int> tmp = qu.front();
			    qu.pop();
			    int x = tmp.first,y = tmp.second;
			    for (int i = 0; i < 4; ++i){
			    	int nx = x+dx[i],ny = y+dy[i];
			    	if(nx>=0 && nx<W && ny>=0 && ny<H && !alt[nx][ny]){
			    		qu.push(make_pair(nx,ny));
			    		alt[nx][ny] = true;
			    	}
			    }
			}
		}
	}
	printf("%d\n", ans);
}

int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	scanf("%d%d%d",&W,&H,&N);
	for(int i= 0;i<N;i++) scanf("%d",&X1[i]);
	for(int i= 0;i<N;i++) scanf("%d",&X2[i]);
	for(int i= 0;i<N;i++) scanf("%d",&Y1[i]);
	for(int i= 0;i<N;i++) scanf("%d",&Y2[i]);
	solve();
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值