现在的位置: 首页 > 综合 > 正文

UVa Problem 10043 Chainsaw Massacre (电锯惊魂)

2012年09月06日 ⁄ 综合 ⁄ 共 2050字 ⁄ 字号 评论关闭
// Chainsaw Massacre (电锯惊魂)
// PC/UVa IDs: 111403/10043, Popularity: B, Success rate: low Level: 3
// Verdict: Accepted
// Submission Date: 2011-11-14
// UVa Run Time: 0.196s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// [解题方法]
// 目标是 O(n^2)的算法,否则容易 TLE。本质是找最一个内部为空的长方形,那么可以依次以一棵数作为
// 左边界,往右扫描确定右边界,当左右边界确定后,就可以确定其面积,然后上下再进行一次同样的扫描,即
// 可确定最终的最大矩形面积。

#include <iostream>
#include <algorithm>

using namespace std;

#define MAXTREES 2500	// 虽然题意是最多只有 1000 棵树,但是可能会有重复的坐标。

struct tree
{
	int x;
	int y;
};

tree trees[MAXTREES];
int l, w;

bool cmpXY(tree a, tree b)
{
	if (a.x == b.x)
		return a.y < b.y;
	return a.x < b.x;
}

bool cmpX(tree a, tree b)
{
	return a.x < b.x;
}

bool cmpY(tree a, tree b)
{
	return a.y < b.y;
}

int main(int ac, char *av[])
{
	int cases, total;
	int k, x, y, dx, dy;

	cin >> cases;
	while (cases--)
	{
		// 注意左边界的处理,可以将有树的行的左边界置为有树。
		cin >> l >> w;

		// 左上角和右下角的可以先 “种” 树,因为矩形可能以此为边界。
		total = 0;
		trees[total++] = (tree){0, 0};
		trees[total++] = (tree){l, w};

		// 读取数据。
		while (cin >> k, k)
		{
			if (k == 1)
			{
				cin >> x >> y;
				trees[total++] = (tree){x, y};
			}
			else
			{
				cin >> x >> y >> dx >> dy;
				for (int i = 1; i <= k; i++)
					trees[total++] = (tree){x + (i - 1) * dx, y + (i - 1) * dy};
			}
		}

		// 去除重复的坐标,可用可不用,用的话可以减少点运行时间,不用,不影响结果。用
		// 快速排序是否可以将时间减得更少?没有尝试过,加上去重复的代码 RT 在 UVa 排
		// 第 35 位。用 map 来表示坐标是否更快?有空试试看能不能进到前 10 位。
		// sort(trees, trees + total, cmpXY);
		// int hole = 1, oldTotal = total;
		// for (int i = 1; i < oldTotal; i++)
			// if (trees[hole - 1].x == trees[i].x && trees[hole - 1].y == trees[i].y)
				// total--;
			// else
				// trees[hole++] = trees[i];

		// 对于每一棵树,以其作为矩形的左边界,往右扫描,直到发现某一列有树,或者达到右
		// 侧边界,则该列为此矩形的右边界。先按横坐标进行排序。
		int maxArea = 0, lowY, topY, leftX, rightX;
		sort(trees, trees + total, cmpX);
		for (int i = 0; i < total; i++)
		{
			lowY = 0;
			topY = w;
			for (int j = i + 1; j < total; j++)
			{
				if (trees[j].x == trees[i].x)
					continue;
				else
				{
					maxArea = max(maxArea, (trees[j].x - trees[i].x) *
                                                (topY - lowY));
					if (trees[j].y < trees[i].y)
						lowY = max(lowY, trees[j].y);
					else
						topY = min(topY, trees[j].y);
				}
			}
		}

		// 先确定上界,再确定下界,再确定矩形,先按纵坐标排序。
		sort(trees, trees + total, cmpY);
		for (int i = 0; i < total; i++)
		{
			leftX = 0;
			rightX = l;
			for (int j = i + 1; j < total; j++)
			{
				if (trees[j].y == trees[i].y)
					continue;
				else
				{
					maxArea = max(maxArea, (trees[j].y - trees[i].y) *
                                                (rightX - leftX));
					if (trees[j].x < trees[i].x)
						leftX = max(leftX, trees[j].x);
					else
						rightX = min(rightX, trees[j].x);
				}
			}
		}
		
		cout << maxArea << endl;
	}

	return 0;
}

抱歉!评论已关闭.