HDU 5925 离散化+dfs

题意:有一个10的9次方乘10的9次方的图,问有几个联通块,每个联通块里面有多少元素。

对于这么大的一个图,直接dfs一定会T。所以我们可以用离散化的方法。把原图拆成由众多矩形构成的图。这样我们可以用离散化,表示出每个矩形顶点的坐标。然后计算每个矩形的面积。给每个矩形是好的还是坏的打上标记。最后dfs一下联通的矩形。既可以得出答案。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
using namespace std;

const int maxx = 200 + 5;
int x[3 * maxx], y[3 * maxx];//一共有200个点,对于每一个点,可以把原图分成8部分。共用3个坐标可以表示。
map<pair<int, int>, int> vis;//数组开不了10的9次方。故用map。
int r, c, n, cntx, cnty;
struct node
{
	long long value;
	bool is;
}mp[maxx * 3][maxx * 3];//每个矩形是否可用,以及覆盖的面积。
vector<long long> ans;
int dx[] = { 1,-1,0,0 };
int dy[] = { 0,0,1,-1 };

long long dfs(int x, int y)
{
	mp[x][y].is = 1;
	long long now = mp[x][y].value;
	for (int i = 0; i < 4; i++)
	{
		int xx = x + dx[i], yy = y + dy[i];
		if (!mp[xx][yy].is&&xx >= 1 && xx <= cntx&&yy >= 1 && yy <= cnty)
			now += dfs(xx, yy);
	}
	return now;
}

int main()
{
	int t;
	scanf("%d", &t);
	for (int i = 1; i <= t; i++)
	{
		scanf("%d%d%d", &r, &c, &n);
		vis.clear(); cntx = 0, cnty = 0;
		for (int i = 1; i <= n; i++)
		{
			int aa, bb;
			scanf("%d%d", &aa, &bb);
			x[++cntx] = aa, y[++cnty] = bb;
			vis[make_pair(aa, bb)] = 1;
			if (aa > 1) x[++cntx] = aa - 1;
			if (bb > 1) y[++cnty] = bb - 1;
			if (aa < r) x[++cntx] = aa + 1;
			if (bb < c) y[++cnty] = bb + 1;
		}//对于每一个点,他的左下方和右上方的点,可以切割原图为8部分。
		x[++cntx] = r, y[++cnty] = c;//保存原图的边界。
		sort(x + 1, x + cntx + 1);
		sort(y + 1, y + cntx + 1);
		cntx = unique(x + 1, x + cntx + 1) - x - 1;
		cnty = unique(y + 1, y + cnty + 1) - y - 1;//去掉重复的点。
		for(int i=1;i<=cntx;i++)
			for (int j = 1; j <= cnty; j++)
			{
				int u, v;
				if (i == 1)u = 1;
				else u = x[i - 1] + 1;
				if (j == 1) v = 1;
				else v = y[j - 1] + 1;//对于i==1和j==1的情况要求矩形面积则要与(1,j)点或(i,1)点相求。//加1的目的是为了防止重复计算面积。
				if (vis[make_pair(x[i], y[j])])
					mp[i][j].is = 1;
				else
					mp[i][j].is = 0;
				mp[i][j].value = (long long)(x[i] - u + 1)*(long long)(y[j] - v + 1);//矩形对角线两点相减求乘积得面积。
			}
		ans.clear();
		for(int i=1;i<=cntx;i++)
			for (int j = 1; j <= cnty; j++)
			{
				long long now = 0;
				if (!mp[i][j].is)
				{
					now += dfs(i, j);
					ans.push_back(now);
				}
			}
		printf("Case #%d:\n", i);
		printf("%d\n", ans.size());
		sort(ans.begin(), ans.end());
		for (int i = 0; i < ans.size(); i++)
		{
			if (i == 0)
				printf("%lld", ans[i]);
			else
				printf(" %lld", ans[i]);
		}
		printf("\n");
	}
	return 0;
}
本人愚见,不喜勿喷。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值