HDOJ 1348 Wall (凸包)

来源:互联网 发布:金九银十的数据 编辑:程序博客网 时间:2024/04/30 05:47

原题链接

一、题目描述

Problem Description
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.
 

Input
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.
 

Output
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.

This problem contains multiple test cases!

The first line of a multiple input is an integer N, then a blank line followed by N input blocks. Each input block is in the format indicated in the problem description. There is a blank line between input blocks.

The output format consists of N output blocks. There is a blank line between output blocks.
 

Sample Input
19 100200 400300 400300 300400 300400 400500 400500 200350 200200 200
 

Sample Output

1628

二、题目分析

           国王要求围墙把城堡围起来,且围墙据城堡的距离为L。而国王的城堡就是许多顶点组成的一个多边形,那么此题就是求平面上的点所围成的凸包问题。

           我们可以先求顶点组成的凸包,然后把凸包各边向外(远离城堡)平移L距离,以满足国王要求。但是,平移后凸包各顶点不在相连,为了确保围墙据城堡距离L,这些顶点之间可以用圆弧连接起来,圆弧半径为L,圆心为城堡各顶点。可以参考题目中给出的样图。

          然后,主要算法就体现在求凸包上。求凸包的算法可以参考这篇博文,比较详细。本文采用了Graham扫描法。


三、AC代码

#include <iostream>#include <algorithm>#include <vector>#include <cmath>using namespace std;const int MAXN = 1005;const double PI = acos(-1.0);const double EPS = 1E-6;int T, N, L;struct Point{int x;int y;} p[MAXN];vector<Point> vec;double dist(Point a, Point b) {return sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));}double crossProduct(Point a, Point b, Point c) { // ab * acreturn (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x) - 0.0;}bool cmp(Point a, Point b) {double cp = crossProduct(p[0], a, b);if (cp > EPS) return true;else if (cp < -EPS) return false;else return dist(p[0], a) < dist(p[0], b);}int findLf(Point p[]) {// find lowest leftest point/vertice.int index = 0;for (int i = 1; i < N; i++) {if (p[i].y < p[index].y) index = i;else if (p[i].y == p[index].y && p[i].x < p[index].x) index = i;}return index;}void graham(Point p[]) {    // graham algorithm for convex hall.vec.clear();vec.push_back(p[0]); vec.push_back(p[1]);int top = 1;for (int i = 2; i < N; i++) {   // another way: i <= N, and comment the line below:ans += dist(vec[vec.size() - 1], vec[0]);while (top >= 1 && crossProduct(vec[top - 1], vec[top], p[i]) <= 0) {vec.pop_back();top--;}vec.push_back(p[i]);top++;}}int main() {cin >> T;while (T--) {cin >> N >> L;for (int i = 0; i < N; ++i) {cin >> p[i].x >> p[i].y;}int lf = findLf(p);swap(p[0], p[lf]);p[N] = p[0];sort(p + 1, p + N, cmp);graham(p);double ans = 0.0;for (int i = 1; i < (int)vec.size(); i++) {ans += dist(vec[i - 1], vec[i]);}ans += dist(vec[vec.size() - 1], vec[0]);ans += 2 * PI * L;cout << (int)round(ans) << endl;if (T) cout << endl;}return 0;}

值得注意的是:在使用Graham算法逆时针扫描各个顶点时,需不需要将起点(代码中的p[0]加入到扫描序列中)。笔者最开始将其加入到序列中。最后发现没必要。不过两者没有多大区别,不加的话,就需要在最后算一下起点和最后一个点的距离。
如上述代码中的:
ans += dist(vec[vec.size() - 1], vec[0]);

       

原创粉丝点击