Sicily 5232.Flood

本文介绍了一种使用离散化处理矩形区域问题的方法,并通过具体示例解释了如何确定安全区域的数量。文中详细阐述了离散化的步骤及深搜算法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本题为2012年校赛第一题。

题意为给出若干个矩形,每个矩形给出左下角和右上角坐标,以最小x和y作为整体区域的左下角坐标,以最大x和y作为整体区域的右上角坐标,矩形区域内不被水淹,水从周围冲来,四周都有保护区域的也不被水淹,连在一起的安全区域算一块,求出安全区域的块数。

在比赛时很遗憾因为这题没做出来,所以没能进省赛。

比赛完看题解,说这题用离散化,其实在比赛时有想过离散化,但是没想出来,结果今天花了一点时间又想了一下,竟然有思路了。

用v[105][105]存储离散化后个区域的状态,最开始都初始为0,1表示安全区域,-1表示被水淹区域。

开始时将所有矩形覆盖区域置为1,然后从外围将所有能被水淹的区域置为-1,最后深搜一下所有非-1的联通块的个数即为答案。

 

测试数据为:

Input:

/*
1
1 1 2 2

2
2 2 3 3
1 3 3 5

2
2 2 3 3
1 3 3 6

3
2 2 3 3
1 3 3 6
8 8 9 9

2
1 3 2 4
2 2 3 3

5
1 1 6 2
1 1 2 7
5 1 6 7
1 6 6 7
3 3 4 4
*/

Output:

/*

1

1

1

2

1

1

*/

 

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;

int v[105][105];        //用于记录各个点的状态
int H,L;            //离散化后的整个区域的高和长
struct node         //用于离散化点
{
	int x, y, n;
};
node n0[210], n1[210];    //将所有矩形的点都离散化
int N;     //矩形个数
int cx[8] ={1,0,-1,0,1,1,-1,-1};
int cy[8] ={0,1, 0, -1,1,-1,1,-1};
bool comp1(node a, node b)        //将点按x排序
{
	if( a.x <= b.x)
		return 1;
	return 0;
}
bool comp2( node a, node b)      //将点按y排序
{
	if( a.y<= b.y)
		return 1;
	return 0;
}
void fun1()                   //离散化各矩形,将离散化后的矩形存在n1中,连续的两个点记录一个矩形
{
	int m=2*N;
	//离散化横坐标
	sort( n0, n0+m, comp1);
	int tem =n0[0].x;
	n0[0].x =0;
	int i,c=0;
	for( i=1; i<m; i++)
	{
		if( n0[i].x ==tem)
		{
			n0[i].x =c;
			continue;
		}
		tem =n0[i].x;
		n0[i].x =(++c);
	}
	L =c;
	//离散化纵坐标
	sort( n0,n0+m, comp2);
	tem =n0[0].y;
	n0[0].y =0;
	c =0;
	for( i=1; i<m; i++)
	{
		if( n0[i].y ==tem)
		{
			n0[i].y =c;
			continue;
		}
		tem =n0[i].y;
		n0[i].y =(++c);
	}
	H =c;
	for( i=0; i<m; i++)
		n1[ n0[i].n ] =n0[i];
}
void dfs1( int a, int b)
{
	v[a][b] =-1;
	int i;
	int nx,ny;
	for( i=0; i<8; i++)
	{
		nx =a+cx[i]; ny =b+cy[i];
		if( nx>=0 && nx<L&& ny>=0 && ny<H && v[nx][ny]!=-1)
			dfs1( nx, ny);
	}
}
void dfs2( int a, int b)
{
	v[a][b] =-1;
	int i;
	int nx,ny;
	for( i=0; i<8; i++)
	{
		nx =a+cx[i]; ny =b+cy[i];
		if( nx>=0 && nx<L&& ny>=0 && ny<H && v[nx][ny]==0)
			dfs2( nx, ny);
	}
}
int fun2()        //遍历不被水淹的区域数
{
	int c=0, i, j;
	for( i=0; i<L; i++)
		for( j=0; j<H; j++)
		{
			if( v[i][j]==1)
			{
				c++;
				dfs1( i, j);
			}
		}
    return c;
}
void fun3()        //将能被水淹的区域标记为-1
{
	int i,j;
	for( i=0; i<H; i++)
	{
		if( v[0][i]==0)
			dfs2(0,i);
		if( v[L-1][i]==0)
			dfs2( L-1,i);
	}
	for( j=0; j<L; j++)
	{
		if( v[j][0] ==0)
			dfs2(j, 0);
		if( v[j][H-1]==0)
			dfs2( j,H-1);
	}
}
int main()
{
	int x0,y0,x1, y1;
	while( scanf("%d", &N)==1 &&N)
	{
		int i,j,k,t;
		for( i=0; i<N; i++)
		{
			scanf("%d%d%d%d", &x0, &y0, &x1, &y1);
			t =i<<1;
			n0[t].x =x0; n0[t].y =y0; n0[t].n =t;
			n0[t+1].x= x1; n0[t+1].y =y1; n0[t+1].n =t+1;
		}
		fun1();
		memset( v, 0,sizeof( v));
		for( i=0; i<N; i++)          //将各矩形区域内标记为1
		{
			t =i<<1;
			x0 =n1[t].x; y0 =n1[t].y;
			x1 =n1[t+1].x; y1=n1[t+1].y;
			for( j=x0; j<x1; j++)
				for( k=y0; k<y1; k++)
					v[j][k] =1;
		}
		fun3();         //标出被水淹部分
		printf("%d\n",fun2());
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值