UVa Problem 10088 Trees on My Island (岛上的树)

// Trees on My Island (岛上的树)
// PC/UVa IDs: 111402/10088, Popularity: C, Success rate: average Level: 3
// Verdict: Accepted
// Submission Date: 2011-11-10
// UVa Run Time: 0.020s
//
// 版权所有(C)2011,邱秋。metaphysis # yeah dot net
//
// [解题方法]
// 运用面积不变的性质,使用多边形面积计算公式和 Pick 定理求解。Pick 定理需要计算边界上的格点数。
// 在本题中需要一点小技巧。

#include <iostream>

using namespace std;

typedef long long int lint;

#define MAXPOLY 1050

struct point
{
	lint x;
	lint y;
};

struct polygon
{
	lint n;
	point p[MAXPOLY];
};

// 求数的绝对值。
lint abs(lint x)
{
	return (x >= 0 ? x : (-x));
}

// 求两数的最大公约数。
lint gcd(lint a, lint b)
{
	if (b == 0)
		return a;

	if (b > a)
		return gcd(b, a);
	else
		return gcd(b, a % b);
}

// 利用有向面积计算多边形的面积。
lint calArea(polygon &contour)
{
	lint total = 0.0;

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

	return abs(total);
}

// 计数多边形边界上的格点。
lint boundaryPolints(polygon &contour)
{
	// 判断在多边形相邻两点之间的连线有多少个格点,实质上是要判断过多边形顶点的直线在给定范围内
	// 整数解的个数。
	lint points = 0;
	for (lint i = 0; i < contour.n; i++)
	{
		lint j = (i + 1) % contour.n;
		
		// 先处理特殊情况。
		if (contour.p[i].x == contour.p[j].x)
			points += (abs(contour.p[j].y - contour.p[i].y) - 1);
		else if (contour.p[i].y == contour.p[j].y)
			points += (abs(contour.p[j].x - contour.p[i].x) - 1);
		else
		{
			// 求横坐标和纵坐标的差的绝对值。
			lint xDiff = abs(contour.p[j].x - contour.p[i].x);
			lint yDiff = abs(contour.p[j].y - contour.p[i].y);

			// 当 x 变化 xDiff 个单位时,y 变化 yDiff 个单位,只要找到这样的
			// 的点:点的横坐标在(min(p[i].x,[j].x),max(p[i].x,[j].x))
			// 范围内且为整数,求这些点的总数,即是此段线段上多边形的边界格点数。
			// 这个可以通过求 xDiff 和 yDiff 的最大公约数(GCD)来得到(为什么
			// ?你可以思考一下,很简单的一个关系)。
			points += gcd(xDiff, yDiff) - 1;
		}
	}
	
	return (points + contour.n);
}

int main (int argc, char const* argv[])
{
	lint vertexNumber;
	polygon contour;
	
	while (cin >> vertexNumber, vertexNumber)
	{
		contour.n = vertexNumber;
		for (lint i = 0; i < vertexNumber; i++)
			cin >> contour.p[i].x >> contour.p[i].y;
		
		// 统计该多边形的边界上的格点数。
		lint vertexBoundary = boundaryPolints(contour);

		// 由多边形面积计算公式计算多边形面积,注意计算结果是面积实际值乘以 2,这样避免
		// 了小数。
		lint area = calArea(contour);

		// Pick 定理。
		cout << (2 * area + 4 - 2 * vertexBoundary) / 4 << endl;	
	}

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值