hdu5925 Coconuts(坐标离散化)

题目

r*c(0<r,c<=1e9)的网格图,有n(0<=n<=200)个障碍点不能被访问,其余点是连通的,

输出这张网格图上的连通块的数量,按增序输出每个连通块的大小

思路来源

归神+涛神

题解

二维离散化裸题

之前一直刻意避着不做,今天终于2h Debug啃过去了

实际的过程和excel里把空白行缩了的过程是一样的……

比如对于左图,就可以缩成三行三列,让中间变成一个点,如右图所示

缩的点记录一下实际代表的水平方向的[l,r]和竖直方向的[l,r],访问这个空白点的时候加一下面积就好了

于是1e9*1e9的图被缩成最大400*400的图,考虑200个点占200个行和列,每两个行和列之间各有一个空白的特殊情形

分别对一维进行离散化,然后二维点就是两个一维的构成的点对

一维离散化的时候,考虑读入的增序排列的已经去重的yi,

①如果y_{1}左边还有空白区域,应将[1,y_{1}-1]加入;

②如果y_{n}右边还有空白区域,应将[y_{n}+1,c]加入

这样不如就直接在排序之前把1和c直接加进y[]数组,就不用特判了

把每个yi离散化成一个[y_{i},y_{i}]的列,两个列之间离散化出一条实际代表[y_{i-1}+1,y_{i}-1]的列

剩余的就是在一个离散化的图上dfs的操作了

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map> 
using namespace std;
const int maxn=450;
typedef long long ll;
struct vertex
{
	ll x,y;
	vertex(){}
}e[maxn];
struct node
{
	ll l,r;
	node(){}
	node(ll L,ll R):l(L),r(R){}
}xx[maxn],yy[maxn];
int t,n,r,c;
ll x[maxn],y[maxn];
int cnt[2],num[2];
map<ll,ll>toX,toY;
bool vis[maxn][maxn];
ll res[maxn],ans,tmp;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
bool ok(int x,int y)
{
	return x>=0&&x<num[0]&&y>=0&&y<num[1]&&!vis[x][y]; 
}
void dfs(int x,int y)
{
	vis[x][y]=1;
	tmp+=(xx[x].r-xx[x].l+1)*(yy[y].r-yy[y].l+1); 
	for(int i=0;i<4;++i)
	{
		int xx=x+dx[i],yy=y+dy[i];
		if(ok(xx,yy))dfs(xx,yy);
	} 
}
void debug()
{
	for(int i=0;i<num[0];++i)
	{
		for(int j=0;j<num[1];++j)
		printf("%4d ",vis[i][j]);
	    puts("");
	}
}
void init()
{
	memset(vis,0,sizeof vis);
	memset(x,0,sizeof x);
	memset(y,0,sizeof y);
	num[0]=num[1]=0;
	ans=0;
	toX.clear();
	toY.clear();
} 
int main()
{
	scanf("%d",&t);
	for(int cas=1;cas<=t;cas++)
	{
		init(); 
		scanf("%d%d",&r,&c);
		scanf("%d",&n);
		for(int i=1;i<=n;++i)
		{
		scanf("%lld%lld",&e[i].x,&e[i].y);
		x[i]=e[i].x;y[i]=e[i].y;
		}
		x[n+1]=1;x[n+2]=r;
		y[n+1]=1;y[n+2]=c;
		sort(x+1,x+n+3);
		sort(y+1,y+n+3);
		cnt[0]=unique(x+1,x+n+3)-(x+1);
		cnt[1]=unique(y+1,y+n+3)-(y+1);
		xx[num[0]]=node(x[1],x[1]);
		toX[x[1]]=num[0]++;
		for(int i=2;i<=cnt[0];++i)
		{
			if(x[i-1]+1<=x[i]-1)xx[num[0]++]=node(x[i-1]+1,x[i]-1);
			xx[num[0]]=node(x[i],x[i]);
			toX[x[i]]=num[0]++;
		}
		yy[num[1]]=node(y[1],y[1]);
		toY[y[1]]=num[1]++;
		for(int i=2;i<=cnt[1];++i)
		{
			if(y[i-1]+1<=y[i]-1)yy[num[1]++]=node(y[i-1]+1,y[i]-1);
			yy[num[1]]=node(y[i],y[i]);
			toY[y[i]]=num[1]++;
		}
		//for(int i=0;i<num[0];++i)
		//printf("x%d:(%d,%d)\n",i,xx[i].l,xx[i].r);
		//for(int i=0;i<num[1];++i)
		//printf("y%d:(%d,%d)\n",i,yy[i].l,yy[i].r);
		for(int i=1;i<=n;++i)
		{
			e[i].x=toX[e[i].x];
			e[i].y=toY[e[i].y];
			//printf("[%d,%d]\n",e[i].x,e[i].y);
			vis[e[i].x][e[i].y]=1;
		}
		//debug();
		for(int i=0;i<num[0];++i)
		{
			for(int j=0;j<num[1];++j)
			{
				if(ok(i,j))
				{
					tmp=0;
					dfs(i,j);
					res[++ans]=tmp;
				}
			}
		}
		printf("Case #%d:\n",cas);
		printf("%lld\n",ans);
		if(ans)
		{
		 sort(res+1,res+ans+1);
		 for(int i=1;i<=ans;++i)
		 printf("%lld%c",res[i],i==ans?'\n':' ');
	    }
	}
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值