【题解】ABC168 F.(Single Dot)

该博客主要讨论了一种算法问题,即在二维平面上,如何通过BFS算法寻找包含点(0,0)的封闭图形的面积。文章提到了坐标离散化、栅栏处理技巧以及搜索策略,通过将栅栏视为左闭右开区间来确保所有可能的边界点都被考虑。最终,算法的时间复杂度为O(nm),并强调了数组大小设置和边界条件检查的重要性。
摘要由CSDN通过智能技术生成

题目描述

给定一个二维平面和一些栅栏,求其中包含点 (0,0) 的封闭图形面积。n,m<=1000

Solution:

模型转化 。首先考虑把横纵坐标离散化,将二维平面转化成网格图。
在这里插入图片描述
显然总面积可以由若干矩形拼成,所以只要 BFS 求出哪些点可达。对于点 (i,j) 可达,面积为 (X[i+1]-X[i])*(Y[j+1]-Y[j])

trick1 :将左边界设为 -1.1e9 ,右边界设为 1.1e9
trick2 :以横栅栏为例,不难发现对于 在栅栏上的点 ,不能向上走; 在栅栏上一格的点,不能向下走,但可以两种情况都可以沿着左右走

下图表示了 (0,0) 可行的路径。
在这里插入图片描述

不难发现黄色节点不没有遍历到。这是一个很棘手的问题。

trick3 :考虑将栅栏设置为 左闭右开 。如此可以遍历到黄色节点。

在这里插入图片描述

因为题目给定了 (0,0) 合法,可以考虑将 (0,0) 作为起点。如果遍历到了边界的点,则输出 -1

trick4 :用 Z[x][y] 来状压 (x,y) 的上下左右 4 个方向 。

时间复杂度 O(nm)

话说这道题因为数组开小等问题 wa 飞了,下次应该避免这种情况。

#include<bits/stdc++.h>
#define mp make_pair
#define ll long long
using namespace std;
const int mx=3005; 
//注意要开三倍空间 
//Task : Atcoder abc
//Author : cqbzly
//思路:离散化 + 搜索
//1. 坐标离散化
//2. 建边
//3. 跑搜索 
int n,m;
int A[mx],B[mx],C[mx],D[mx],E[mx],F[mx];
int X[mx],Y[mx],XC,YC,Z[mx][mx],K[mx][mx];
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
queue<pair<int,int> > Q;
int getx(int x) {
	return lower_bound(X,X+XC,x)-X;
}
int gety(int x) {
	return lower_bound(Y,Y+YC,x)-Y;
}
int main() {
//	freopen("data.in","r",stdin);	
//	freopen("data.out","w",stdout);
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		cin>>A[i]>>B[i]>>C[i];
		X[XC++]=A[i];
		X[XC++]=B[i];
		Y[YC++]=C[i];
	}
	for(int i=1;i<=m;i++) {
		cin>>D[i]>>E[i]>>F[i];
		X[XC++]=D[i];
		Y[YC++]=E[i];
		Y[YC++]=F[i];
	}
	X[XC++]=-1.1e9;
	X[XC++]=0;
	X[XC++]=1.1e9;
	Y[YC++]=-1.1e9;
	Y[YC++]=0;
	Y[YC++]=1.1e9;
	sort(X,X+XC),sort(Y,Y+YC);
	XC=unique(X,X+XC)-X-1,YC=unique(Y,Y+YC)-Y-1;
	for(int i=1;i<=n;i++) {
		A[i]=getx(A[i]);
		B[i]=getx(B[i]);
		C[i]=gety(C[i]);
		for(int j=A[i];j<B[i];j++) {
			Z[j][C[i]-1]|=1<<0;
			Z[j][C[i]]|=1<<2;
		}
	}
	for(int i=1;i<=m;i++) {
		D[i]=getx(D[i]);
		E[i]=gety(E[i]);
		F[i]=gety(F[i]);
		for(int j=E[i];j<F[i];j++) {
			Z[D[i]-1][j]|=1<<1;
			Z[D[i]][j]|=1<<3;
		} 
	}
	int sx=getx(0),sy=gety(0);
	Q.push(mp(sx,sy)),K[sx][sy]=1;
	while(Q.size()) {
		int x=Q.front().first,y=Q.front().second; Q.pop();
//		cout<<X[x]<<" "<<Y[y]<<endl;
		for(int i=0;i<4;i++) {
			if(~ Z[x][y] & (1<<i) ) {
				int tx=x+dx[i],ty=y+dy[i];
				if(tx<0||tx>=XC||ty<0||ty>=YC) continue;
				if(!K[tx][ty]) {
					K[tx][ty]=1;
					Q.push(mp(tx,ty));
				}
			}
		}
	}
	for(int i=0;i<XC;i++) {
		if(K[i][0] || K[i][YC-1]) {
			cout<<"INF";
			return 0;
		}
	}
	for(int i=0;i<YC;i++) {
		if(K[0][i] || K[XC-1][i]) {
			cout<<"INF";
			return 0;
		}
	}
	ll area(0);
	for(int i=1;i<XC;i++) {
		for(int j=1;j<YC;j++) {
			if(K[i][j]) {
				area+=1LL*(X[i+1]-X[i])*(Y[j+1]-Y[j]);
			}
		}
	}
	cout<<area;
 }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值