#include <bits/stdc++.h> #define LL long long #define eps 1e-7 #define zero(a) fabs(a)<eps const int INF = 0x3f3f3f3f; const int N = 20; const double pi = acos(-1.0); int n; using namespace std; struct Point { double x, y, val; } p[100], t[100], pre, cur; struct Segment { Point a, b; }; inline double xmul(Point p0, Point p1, Point p2)//差乘 { return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y); } inline double dist(Point p1, Point p2) { return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); } inline double Dist_Point_Seg(Point p, Point a, Point b)//点到直线距离 { Point t = p; t.x += a.y - b.y; t.y += b.x - a.x; if (xmul(a, t, p)*xmul(b, t, p) > eps) return dist(p, a) + eps < dist(p, b) ? dist(p, a) : dist(p, b); else return fabs(xmul(p, a, b)) / dist(a, b); } inline bool online(Point p1, Point p2, Point p)//点在线上 { if (zero(xmul(p1, p2, p)) && ((p.x - p1.x) * (p.x - p2.x) < eps && (p.y - p1.y) * (p.y - p2.y) < eps)) return true; return false; } inline bool across(Segment s1, Segment s2)// 线段相交 { if (xmul(s1.a, s1.b, s2.a)*xmul(s1.a, s1.b, s2.b) < eps) if (xmul(s2.a, s2.b, s1.a)*xmul(s2.a, s2.b, s1.b) < eps) return true; return false; } inline bool Parallel(Segment s1, Segment s2)//平行 { return zero((s1.a.x - s1.b.x) * (s2.a.y - s2.b.y) - (s2.a.x - s2.b.x) * (s1.a.y - s1.b.y)); } inline bool In_Polygon(Point cen)//判断在多边形内 { int cnt = 0; Segment s, e; s.a = cen; s.b.y = cen.y; s.b.x = 20000.0; for (int i = 0; i < n; i++) { e.a = p[i]; e.b = p[i + 1]; if (online(p[i], p[i + 1], cen)) return false; if (zero(p[i].y - p[i + 1].y)) continue; if (online(s.a, s.b, p[i])) { if (p[i].y > p[i + 1].y) cnt++; } else if (online(s.a, s.b, p[i + 1])) { if (p[i + 1].y > p[i].y) cnt++; } else if (across(s, e)) cnt++; } return cnt & 1; } inline void Get_Min_Dist(Point &cur)//点到多边形的最短距离 { double ret = INF; for (int i = 0; i < n; i++) ret = min(ret, Dist_Point_Seg(cur, p[i], p[i + 1])); cur.val = ret; } int main(int argc, char const *argv[]) { double r, best[105]; srand(time(NULL)); while (cin >> n && n) { double maxx = 0, maxy = 0, minx = INF, miny = INF; for (int i = 0; i < n; i++) { cin >> p[i].x >> p[i].y; maxx = max(maxx, p[i].x); maxy = max(maxy, p[i].y); minx = min(minx, p[i].x); miny = min(miny, p[i].y); } p[n] = p[0]; cin >> r; int m = min(n, N); for (int i = 0; i < m; i++)//从线段中点开始运动 { t[i].x = (p[i].x + p[i + 1].x) / 2.0; t[i].y = (p[i].y + p[i + 1].y) / 2.0; t[i].val = 0; } bool ok = 0; for (double step = sqrt((maxx - minx) * (maxx - minx) + (maxy - miny) * (maxy - miny)) / 2; step > 1e-3 && !ok; step *= 0.55)//模拟退火 for (int i = 0; i < m && !ok; ++i)//对于每一个点都计算提高几率 for (int j = 0; j < 5 && !ok; j++)//提高几率 { double angle = rand(); cur.x = t[i].x + step * cos(angle); cur.y = t[i].y + step * sin(angle); if (!In_Polygon(cur))continue;// 点跳出了多边形 Get_Min_Dist(cur);//在这个点最大的R if (cur.val + 1e-3 > t[i].val) { t[i] = cur; if (cur.val + 1e-3 > r) ok = 1; } } cout << (ok ? "Yes" : "No") << endl; } return 0; }
几何题,一个任意多边形,判断是否能放入一个半径为r的圆;
卡卡卡卡卡了好久,看了题解才知道还是too young
http://blog.csdn.net/ACM_cxlove/article/details/7898178
模拟退火关键问题在于火候怎么把握,一开始尝试选取n个点,步长每次减小1/10,精度控制在1e-3,竟然TLE,看了网上的代码,也是这么多。
然后开始各种尝试,果断减小选取的点数。各种WA,TLE无语。。。
有位好心的ACMER,给了一组数据
4
0 0
0 2
2 2
2 0
1
一般如果在判断的时候要求精度太高的话,这组数据过不了,果断不原本1e-8的精度改成1e-3,一通乱改之后,可以说是勉强通过了这组数据。
大清早的起来又是刷屏,各种尝试火候,最终还是刷进了200ms
最多选 20个点,每个点走5步,步长为原来的0.55,之前的TLE主要原因就是那组数据出不来,而且会WA。