TZOJ1471: Wall(凸包Andrew算法)

题目:

描述

Once upon a time there was a greedy King who ordered his chief Architect to build a wall around the King's castle. The King was so greedy, that he would not listen to his Architect's proposals to build a beautiful brick wall with a perfect shape and nice tall towers. Instead, he ordered to build the wall around the whole castle using the least amount of stone and labor, but demanded that the wall should not come closer to the castle than a certain distance. If the King finds that the Architect has used more resources to build the wall than it was absolutely necessary to satisfy those requirements, then the Architect will loose his head. Moreover, he demanded Architect to introduce at once a plan of the wall listing the exact amount of resources that are needed to build the wall.


Your task is to help poor Architect to save his head, by writing a program that will find the minimum possible length of the wall that he could build around the castle to satisfy King's requirements.
The task is somewhat simplified by the fact, that the King's castle has a polygonal shape and is situated on a flat ground. The Architect has already established a Cartesian coordinate system and has precisely measured the coordinates of all castle's vertices in feet.

输入

The first line of the input file contains two integer numbers N and L separated by a space. N (3 <= N <= 1000) is the number of vertices in the King's castle, and L (1 <= L <= 1000) is the minimal number of feet that King allows for the wall to come close to the castle.
Next N lines describe coordinates of castle's vertices in a clockwise order. Each line contains two integer numbers Xi and Yi separated by a space (-10000 <= Xi, Yi <= 10000) that represent the coordinates of ith vertex. All vertices are different and the sides of the castle do not intersect anywhere except for vertices.

输出

Write to the output file the single number that represents the minimal possible length of the wall in feet that could be built around the castle to satisfy King's requirements. You must present the integer number of feet to the King, because the floating numbers are not invented yet. However, you must round the result in such a way, that it is accurate to 8 inches (1 foot is equal to 12 inches), since the King will not tolerate larger error in the estimates.

样例输入

5 100
200 400
500 400
500 200
350 200
200 200

样例输出

1628

提示

结果四舍五入就可以了

题意:

从前,有一位贪婪的国王命令他的首席建筑师在国王的城堡周围建造一堵墙。国王是如此贪婪,以至于他不会听从建筑师的建议,建造一堵形状完美的美丽砖墙和高塔。相反,他下令用最少的石头和劳动力在整个城堡周围建造城墙,但要求城墙不能靠近城堡超过一定距离。如果国王发现建筑师使用的资源超过了满足这些要求绝对必要的资源,那么建筑师就会失去脑袋。此外,他要求建筑师立即画出隔离墙的平面图,列出建造隔离墙所需的确切资源数量。


你的任务是帮助可怜的建筑师拯救他的脑袋,通过编写一个程序,找到他可以在城堡周围建造的最小长度的墙,以满足国王的要求。
由于国王的城堡呈多边形形状并且位于平坦的地面上,因此任务得到了一定的简化。建筑师已经建立了一个坐标系,并以英尺为单位精确测量了城堡所有顶点的坐标。

输入

输入文件的第一行包含两个整数 N 和 L,用空格分隔。N(3 <= N <= 1000)是国王城堡中的顶点数,L (1 <= L <= 1000)是国王允许城墙靠近城堡的最小英尺数。
接下来的N行按顺时针顺序描述城堡顶点的坐标。每条线包含两个整数 Xi 和 Yi,由空格 (-10000 <= Xi, Yi <= 10000) 分隔,表示第 i 个顶点的坐标。所有顶点都是不同的,城堡的侧面除了顶点外,在任何地方都不相交。

输出

将单个数字写入输出文件,该数字表示可以在城堡周围建造的最小可能长度(以英尺为单位)以满足国王的要求。您必须向国王出示英尺的整数,因为浮点数尚未发明。但是,您必须对结果进行四舍五入

理解题意后就明白这题是凸包问题,但是这里还有一个距离的限制条件,那么我们把点都变成半径为L的圆, 将这些外围的点合在一起就变成了一个半径为L的完整的圆了,所以城墙的最小英尺数就等于凸包的长度加一个半径为L的圆的长度。

计算几何入门 1.1:凸包的概念_HouszChina的博客-CSDN博客_凸包

 

凸包问题有两种求法:Graham算法和Andrew算法,两种算法都需要对点排序,时间复杂度均为O(nlogn)。

Andrew算法:

#include <bits/stdc++.h>
#define x first
#define y second
#define PI 3.1415926
using namespace std;

const int N = 1e3 + 5;
int n, top;//top表示栈顶
double l;
typedef pair<double, double> PDD;
PDD p[N], s[N];

double cross(PDD A, PDD B, PDD C) {
	double x1 = B.x - A.x;
	double y1 = B.y - A.y;//AB向量的x和y
	double x2 = C.x - A.x;
	double y2 = C.y - A.y;
	return x1 * y2 - x2 * y1;//二维叉积公式
}

double dis(PDD A, PDD B) {
	return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));//计算两点之间的距离
}

double Andrew() {
	sort(p, p + n);//sort默认先对pair.first从小到大排序,如果相等,再对pair.second从小到大排序
	for (int i = 0; i < n; i++) {//顺序遍历记录下凸包
		while (top >= 2 && cross(s[top - 1], s[top], p[i]) <= 0)//top>=2先在栈中放入两个点,不让后面的叉积判断越界,如果叉积<=0说明点在直线右侧或在直线上,此时弹出栈顶
			top--;
		s[++top] = p[i];
	}
	int t = top;
	for (int i = n - 2; i >= 0; i--) {//逆序遍历记录上凸包,此时n-1这个点一定已经入栈因为第一个点和n-1这个点一定是最外层的,这样我们从n-2开始入栈
		while (top > t && cross(s[top - 1], s[top], p[i]) <= 0)//top>t确保n-2也入栈,这样就有两个点连成一条直线
			top--;
		s[++top] = p[i];
	}
	double ans = 2 * PI * l;//圆面积
	for (int i = 1; i < top; i++) {
		ans += dis(s[i], s[i + 1]);//两点直线距离
	}
	return ans;
}

int main() {
	scanf("%d%lf", &n, &l);
	for (int i = 0; i < n; i++)
		scanf("%lf%lf", &p[i].x, &p[i].y);
	printf("%.0f", Andrew() + 0.5);//四舍五入,结果加0.5取整
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值