UVa Problem 922 - Rectangle by the Ocean

// UVa Problem 922 - Rectangle by the Ocean
// Verdict: Accepted
// Submission Date: 2011-11-08
// UVa Run Time: 0.028s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// [解题方法]
// 本题为计算几何题,使用有向面积计算多边形的面积。使用穷举法枚举可能的矩形左下角和右上角坐标,判断
// 矩形是否至少有三个角落在多边形上,注意枚举时的坐标选择顺序,可以适当的选择自动得到最小字典序的
// 结果。

#include <iostream>
#include <cmath>

using namespace std;

#define MAXPOLY 300

struct point
{
	int x;
	int y;
};

struct rect
{
	int left, lower;
	int right, upper;
};

struct polygon
{
	int n;
	int top, left, right, bottom;
	point p[MAXPOLY];
};

// 点(i,j)是否在多边形上。
int on[MAXPOLY][MAXPOLY];

// 使用穷举法逐个枚举可能矩形的左下角和右上角坐标。
void rectangle(polygon &contour, double area)
{
	double minDiff = area, currentDiff;
	rect tmp;

	// 初始化。
	for (int i = 0; i <= (contour.right - contour.left); i++)
		for (int j = 0; j <= (contour.top - contour.bottom); j++)
			on[i][j] = 0;

	// 将多边形上的点标记为在多边形上,除此之外,在多边形外接矩形内的点均不在多边形上。注意
	// 坐标的变换。
	for (int i = 0; i < contour.n; i++)
		on[contour.p[i].x - contour.left][contour.p[i].y - contour.bottom] = 1;

	// 枚举可能的矩形,注意枚举的顺序。
	for (int i = 0; i <= contour.right - contour.left; i++)
		for (int j = 0; j <= contour.top - contour.bottom; j++)
			for (int m = i; m <= contour.right - contour.left; m++)
				for (int n = j; n <= contour.top - contour.bottom; n++)
				{
					// 判断是否符合至少三个角落在多边形上的条件。
					if (on[i][j] + on[i][n] +
						on[m][j] + on[m][n] < 3)
						continue;

					// 比较差值,注意是 “尽可能接近“,应取绝对值。
					currentDiff = fabs((m - i) * (n - j) - area);
					if (currentDiff < minDiff)
					{
						minDiff = currentDiff;
						tmp = (rect) {
						contour.left + i,
						contour.bottom + j,
						contour.left + m,
						contour.bottom + n };
					}
				}

	// 输出结果。
	cout << ((int)(area)) << "." << ((int)(area * 10.0) % 10) << " ";
	cout << tmp.left << " " << tmp.lower << " ";
	cout << tmp.right << " " << tmp.upper << endl;
}

// 由多边形的顶点坐标求多边形的面积。
double calArea(polygon &contour)
{
	double total = 0.0;

	for (int i = 0; i < contour.n; i++)
	{
		int j = (i + 1) % contour.n;
		total += (contour.p[i].x * contour.p[j].y -
				contour.p[j].x * contour.p[i].y);
	}

	return fabs(total / 2.0);
}

int main(int ac, char *av[])
{
	int cases;
	polygon contour;

	cin >> cases;
	while (cases--)
	{
		cin >> contour.n;
		for (int i = 0; i < contour.n; i++)
			cin >> contour.p[i].x >> contour.p[i].y;

		// 找到多边形外接矩形边界。
		contour.top = contour.p[0].y;
		contour.left = contour.p[0].x;
		contour.bottom = contour.p[0].y;
		contour.right = contour.p[0].x;
		for (int i = 1; i < contour.n; i++)
		{
			contour.top = max(contour.top, contour.p[i].y);
			contour.left = min(contour.left, contour.p[i].x);
			contour.bottom = min(contour.bottom, contour.p[i].y);
			contour.right = max(contour.right, contour.p[i].x);
		}

		rectangle(contour, calArea(contour));
	}

	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值