1. 程式人生 > >HDU-3644 A Chocolate Manufacturer's Problem 計算幾何 模擬退火

HDU-3644 A Chocolate Manufacturer's Problem 計算幾何 模擬退火

題意: 給定一個多邊形, 判斷這個多邊形中是否可以放入一個半徑為r的圓. 分析: 發現不知從何入手時就開始模擬退火吧. 隨機找出圓心座標, 主要就是判斷某個點是否在多邊形內. 這題wa和tle了好多次, 引數選擇需要些微調, 模擬退火有風險, 罰時傷不起. 程式碼:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <iostream>

using namespace
std; const int MAXN = 111; const double pi = acos(-1); const double inf = 0x3f3f3f3f; const double eps = 1e-4; int sgn(double x) { if (fabs(x) < eps) return 0; else if (x < 0) return -1; else return 1; } struct Point { double x, y; Point() {} Point(double _x, double _y)
{ x = _x; y = _y; } Point operator+(const Point b) const { return Point(x + b.x, y + b.y); } Point operator-(const Point b) const { return Point(x - b.x, y - b.y); } double operator*(const Point b) const { return x * b.x + y * b.y; } double operator^(const Point b) const { return
x * b.y - y * b.x; } bool operator==(const Point b) { return sgn(x - b.x) == 0 && sgn(y - b.y) == 0; } double distance(Point b) { return hypot(x - b.x, y - b.y); } }; struct Line { Point s, e; Line() {} Line(Point _s, Point _e) { s = _s; e = _e; } double length() { return s.distance(e); } double dispointtoline(Point b) { return fabs((b - s) ^ (e - s)) / length(); } double dispointtoseg(Point b) { if (sgn((b - s) * (e - s)) < 0 || sgn((b - e) * (s - e)) < 0) return min(b.distance(s), b.distance(e)); else return dispointtoline(b); } bool pointonseg(Point b) { return sgn((b - s) ^ (e - s)) == 0 && sgn((b - s) * (b - e)) <= 0; } }; struct Polygon { Point p[MAXN]; Line l[MAXN]; int n; void add(Point b) { p[n++] = b; } void getline() { for (int i = 0; i < n; i++) { l[i] = Line(p[i], p[(i + 1) % n]); } } int relationpoint(Point q) { for (int i = 0; i < n; i++) { if (p[i] == q) return 3; } getline(); for (int i = 0; i < n; i++) { if (l[i].pointonseg(q)) return 2; } int cnt = 0; for (int i = 0; i < n; i++) { int j = (i + 1) % n; int k = sgn((q - p[i]) ^ (p[i] - p[j])); int u = sgn(p[i].y - q.y); int v = sgn(p[j].y - q.y); if (k > 0 && u < 0 && v >= 0) cnt++; if (k < 0 && v < 0 && u >= 0) cnt--; } return cnt != 0; } double getdis(Point cir) { double res = inf; getline(); for (int i = 0; i < n; i++) { res = min(res, l[i].dispointtoseg(cir)); } // cout << res << endl; return res; } }; Polygon pol; int n; double r; Point ans[MAXN]; double Rand() { return (double)rand() / RAND_MAX; } int main() { srand(time(NULL)); while (scanf("%d", &n) != EOF) { if (n == 0) break; pol.n = 0; for (int i = 0; i < n; i++) { double x, y; scanf("%lf%lf", &x, &y); pol.add(Point(x, y)); } scanf("%lf", &r); double x1 = pol.p[0].x, x2 = pol.p[0].x, y1 = pol.p[0].y, y2 = pol.p[0].y; for (int i = 0; i < n; i++) { ans[i].x = (pol.p[i].x + pol.p[(i + 1) % n].x) / 2.0; ans[i].y = (pol.p[i].y + pol.p[(i + 1) % n].y) / 2.0; x1 = min(x1, pol.p[i].x); x2 = max(x2, pol.p[i].x); y1 = min(y1, pol.p[i].y); y2 = max(y2, pol.p[i].y); } double res = -inf; double T = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) / 2; // cout << " --------------- " << endl; bool flag = 0; while (T > eps && !flag) { for (int j = 0; j < n; j++) { for (int i = 0; i < 5; i++) { Point nxt; nxt.x = ans[j].x + T * (Rand() * 2 - 1); nxt.y = ans[j].y + T * (Rand() * 2 - 1); if (pol.relationpoint(nxt) != 1) continue; // cout << nxt.x << " " << nxt.y << endl; double dis = pol.getdis(nxt); if (sgn(res - dis) < 0) { res = dis; ans[j] = nxt; if (sgn(res - r) >= 0) flag = 1; } } } T *= 0.9; } // cout << res << endl; printf("%s\n", !flag ? "No" : "Yes"); } return 0; }