ALGO-185 Trash Removal

```
算法训练 Trash Removal
时间限制:1.0s 内存限制:256.0MB

问题描述
  Allied Chute公司是一个建造垃圾管道的公司。垃圾管道建造在楼房中,垃圾从顶部进入,顺着管道与地下室连接。建造垃圾管道是一个高水平的工作。根据人们丢入不同种类的垃圾,垃圾管道需要有一个适当的尺寸。并且由于制作垃圾管道的费用正比于它的尺寸,公司总是想要建造尽可能的管道,尽管确定合适的尺寸十分困难。
  为了简化这个问题,我们考虑一个二维的空间。垃圾管道是一个有着固定宽度、垂直下降的槽。物体可以看作一个多边形的模型。在物体落入管道之前它可以旋转来达到和管道最佳拟合。当它下落时,它会垂直落下并且不再旋转。下图展示了一个垃圾是怎样旋转来符合管道的。
  你的任务是计算让一个给定的多边形物体通过的最小管道宽度。
输入格式
  输入包含多组数据。每组数据开始于一个数字n,代表垃圾的模型—一个多边形的顶点数。
  接下来n行每行一对整数xi和yi,按顺序给出多边形的顶点。
  最后以一个0表示结束
输出格式
  对于每组测试数据,输出数据编号以 及物体能够穿过垃圾管道并落下的最小宽度。输出的最小宽度并 向上舍入到最接近1/100倍数的数 ,你的答案与标准答案误差不能超过1/100。
样例输入
3
0 0
3 0
0 4
4
0 10
10 0
20 10
10 20
0
样例输出
Case 1: 2.40
Case 2: 14.15
数据规模和约定
  30%的数据3<=n<=15
  100%的数据3<=n<=100
  0<=xi,yi<=10^4
  保证在一组数据中的所有的点互不不同,并且多边形的边不会相交(技术上,两条相邻的边不可避免的会有一个公共顶点,当然,这种情况我们不认为是相交)。
```

```c++
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;

struct Point {
double x, y;

Point(double a = 0, double b = 0) : x(a), y(b) {}

Point operator - (const Point &b) const {
return Point(x - b.x, y - b.y);
}

bool operator < (const Point &b) const {
return x < b.x || (x == b.x && y < b.y);
}

double norm(){//模的长度
return sqrt(x * x + y * y);
}
};

//计算a与b(向量积)的值
double cross(Point a, Point b) {
return a.x * b.y - a.y * b.x;
}

//判断b在a顺时针还是逆时针
bool IsClockWise(Point p0, Point p1, Point p2) {
if (cross(p1 - p0, p2 - p1) < 0)
return true;
else
return false;
}

//安德鲁算法(Andrew’s Algorithm)求凸包
int Andrew(Point *res, Point *p, int n) {
sort(p, p+n);
int m = 0; //凸包集合计数索引
for (int i = 0; i < n; i++) { //从左向右扫描,创建凸包的上部
while (m >= 2 && !IsClockWise(res[m-2], res[m-1], p[i]))
m--;
res[m++] = p[i];
}
int k = m;
for (int i = n - 2; i >= 0; i--) { //从n-2开始是因为n-1一定在凸包的上部分,已包含,
while (m > k && !IsClockWise(res[m-2], res[m-1], p[i]))
m--;
res[m++] = p[i];
}
if (m > 0) m--;
return m;
}

//求点到边的距离
double DistanceToLine(Point p, Point a, Point b) {
double buttom = (a-b).norm();
return fabs(cross(a-p, b-p)) / buttom;
}

int main() {
Point res[105],p[105];
int n;
int cnt = 1;
while (cin >> n && n) {
for (int i = 0; i < n; i++)
cin >> p[i].x >> p[i].y;
int m = Andrew(res, p, n);
double ans = INFINITY;
//枚举每一条边作为低,求高的最小值。i取值从0~m,形成一个换
for (int i = 0; i <= m; i++) {
double max_high = 0.0;
for (int j = 0; j < m; j++) {
max_high = max(max_high, DistanceToLine(res[j], res[i], res[(i+1)%m]));
}
ans = min(ans,max_high);
}
ans = ceil(ans * 100) / 100;
cout << "Case " << cnt++ << ": " << ans << endl;
}
return 0;
}
```

原文地址:https://www.cnblogs.com/zhanyeye/p/10246592.html