// Useless Tile Packers (没用的瓷砖打包公司) // PC/UVa IDs: 111405/10065, Popularity: C, Success rate: average Level: 3 // Verdict: Accepted // Submission Date: 2011-11-06 // UVa Run Time: 0.020s // // 版权所有(C)2011,邱秋。metaphysis # yeah dot net // // [解题方法] // 简单的求凸包和面积问题,思考后解决应该不难。 #include <iostream> #include <algorithm> #include <iomanip> #include <cmath> using namespace std; #define MAXPOLY 105 struct point { int x; int y; }; struct polygon { int vertexNumber; point vertex[MAXPOLY]; }; // 利用有向面积计算多边形的面积,注意最后结果取绝对值,因为顶点顺序可能并不是按逆时针方向给出。 double area(point vertex[], int vertexNumber) { double total = 0.0; for (int i = 0; i < vertexNumber; i++) { int j = (i + 1) % vertexNumber; total += (vertex[i].x * vertex[j].y - vertex[j].x * vertex[i].y); } return fabs(total / 2.0); } // 叉积,判断点 first,second,third 组成的两条线段的转折方向。当叉积大于 0,则形成一个右拐, // 否则共线(cp = 0)或左拐(cp > 0)。 int crossProduct(point first, point second, point third) { return (second.x - first.x) * (third.y - first.y) - (second.y - first.y) * (third.x - first.x); } // Andrew 凸包扫描算法的预排序,先按 x 坐标排序,若 x 坐标相同,则按 y 坐标排序。 bool left_lower(point first, point second) { if (first.x == second.x) return first.y < second.y; else return first.x < second.x; } // Andrew 凸包扫描算法。 void convex_hull(point vertex[], int vertexNumber, polygon &container) { // 点个数小于等于三个,构成凸包。 if (vertexNumber <= 3) { for (int i = 0; i < vertexNumber; i++) container.vertex[i] = vertex[i]; container.vertexNumber = vertexNumber; return; } // 排序。 sort(vertex, vertex + vertexNumber, left_lower); point upper[MAXPOLY], lower[MAXPOLY]; int top; // 求上凸包。 upper[0] = vertex[0]; upper[1] = vertex[1]; top = 2; for (int i = 2; i < vertexNumber; i++) { upper[top] = vertex[i]; while (top >= 2 && crossProduct(upper[top - 2], upper[top - 1], upper[top]) >= 0) { upper[top - 1] = upper[top]; top--; } top++; } container.vertexNumber = 0; for (int i = 0; i < top; i++) container.vertex[container.vertexNumber++] = upper[i]; // 求下凸包。 lower[0] = vertex[vertexNumber - 1]; lower[1] = vertex[vertexNumber - 2]; top = 2; for (int i = vertexNumber - 3; i >= 0; i--) { lower[top] = vertex[i]; while (top >= 2 && crossProduct(lower[top - 2], lower[top - 1], lower[top]) >= 0) { lower[top - 1] = lower[top]; top--; } top++; } // 合并下凸包。 for (int i = 1; i < top - 1; i++) container.vertex[container.vertexNumber++] = lower[i]; } int main(int ac, char *av[]) { point tile[MAXPOLY]; polygon container; int vertexNumber, currentCase = 1; cout.precision(2); cout.setf(ios::fixed | ios::showpoint); while (cin >> vertexNumber, vertexNumber) { for (int i = 0; i < vertexNumber; i++) { cin >> tile[i].x; cin >> tile[i].y; } double used = area(tile, vertexNumber); convex_hull(tile, vertexNumber, container); cout << "Tile #" << currentCase++ << endl; double all = area(container.vertex, container.vertexNumber); double rate = (1.0 - used / all) * 100.0; cout << "Wasted Space = " << rate << " %" << endl; cout << endl; } return 0; }