HDU 4766 模拟退火(最小圆覆盖) + 二分

来源:互联网 发布:coc女王升级数据 编辑:程序博客网 时间:2024/04/26 21:54
#include <cstdio>#include <cstring>#include <cmath>#include <vector>#include <iostream>#include <algorithm>const int maxn = 1E3 + 10;using namespace std;struct Point{double x, y;Point(double x = 0, double y = 0): x(x), y(y) {}};typedef Point Vector;typedef vector<Point> Polygon;Vector operator +(Vector A, Vector B)//{return Vector(A.x + B.x, A.y + B.y);}Vector operator -(Point A, Point B)//{return Vector(A.x - B.x , A.y - B.y);}Vector operator *(Vector A, double p)//{return Vector(A.x * p, A.y * p);}Vector operator /(Vector A, double p)//{return Vector(A.x / p, A.y / p);}bool operator <(const Point &a, const Point &b)//{return a.x < b.x || (a.x == b.x && a.y < b.y);}const double eps = 1e-6;int dcmp(double x)//{if (fabs(x) < eps) return 0;else return x < 0 ? -1 : 1;}bool operator ==(const Point &a, const Point &b)//{return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0;}double Dot(Vector A, Vector B)//{return A.x * B.x + A.y * B.y;}double Length(Vector A)//{return sqrt(Dot(A, A));}double Cross(Vector A, Vector B)//{return A.x * B.y - A.y * B.x;}double Distance(Point A, Point B){return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));}double Distance2(Point A, Point B){return (A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y);}double DistanceToLine(Point p, Point A, Point B) //{Vector v1 = B - A, v2 = p - A;return fabs(Cross(v1, v2)) / Length(v1);}Vector Normal(Vector A)//{double L = Length(A);return Vector(-A.y / L, A.x / L);}double Angle(Vector A, Vector B)//{return acos(Dot(A, B) / Length(A) / Length(B));}struct Line{Point p;Vector v;double ang;Line() {};Line(Point P, Vector v): p(P), v(v) {ang = atan2(v.y, v.x);}bool operator < (const Line& L) const{return ang < L.ang;}Point point(double t){return p + v * t;}Line move(double d){return Line(p + Normal(v) * d, v);}};struct Circle{Point c;double r;Circle(Point c, double r): c(c), r(r) {}Point point(double a){return Point(c.x + cos(a) * r, c.y + sin(a) * r);}};int getLineCircleIntersection(Line L, Circle C, double& t1, double& t2, vector<Point>& sol){double a = L.v.x, b = L.p.x - C.c.x, c = L.v.y, d = L.p.y - C.c.y;double e = a * a + c * c, f = 2 * (a * b + c * d), g = b * b + d * d - C.r * C.r;double delta = f * f - 4 * e * g; // 判别式if (dcmp(delta) < 0) return 0; // 相离if (dcmp(delta) == 0)  // 相切{t1 = t2 = -f / (2 * e); sol.push_back(L.point(t1));return 1;}// 相交t1 = (-f - sqrt(delta)) / (2 * e); sol.push_back(L.point(t1));t2 = (-f + sqrt(delta)) / (2 * e); sol.push_back(L.point(t2));return 2;}double angle(Vector v) {return atan2(v.y, v.x);}int GetCircleCircleIntersection(Circle C1, Circle C2, Point &A, Point &B){double d = Length(C1.c - C2.c);if (dcmp(d) == 0){if (dcmp(C1.r - C2.r) == 0) return -1; // 重合,无穷多交点return 0;}if (dcmp(C1.r + C2.r - d) < 0) return 0;if (dcmp(fabs(C1.r - C2.r) - d) > 0) return 0;double a = angle(C2.c - C1.c);double da = acos((C1.r * C1.r + d * d - C2.r * C2.r) / (2 * C1.r * d));Point p1 = C1.point(a - da), p2 = C1.point(a + da);A = p1;if (p1 == p2) return 1;B = p2;return 2;}int n;Point P[maxn], p0;double R[maxn], d;bool Judge(double mid){double Left, Right;for (int i = 0; i <= n; i++){if (i == 0){Left = P[i].x - R[i];Right = P[i].x + R[i];}else{if (P[i].x - R[i] > Left) Left = P[i].x - R[i];if (P[i].x + R[i] < Right) Right = P[i].x + R[i];}}if (Left - Right > eps) return false;int step = 50;while (step--){double mid = (Left + Right) * 0.5;double low, high, uy, dy;int low_id, high_id;for (int i = 0; i <= n; i++){double d = sqrt(R[i] * R[i] - (P[i].x - mid) * (P[i].x - mid));uy = P[i].y + d;dy = P[i].y - d;if (i == 0){low_id = high_id = 0;low = dy; high = uy;}else{if (uy < high) high = uy, high_id = i;if (dy > low) low = dy, low_id = i;}}if (high - low > -eps){return 1;}Point a, b;if (GetCircleCircleIntersection(Circle(P[high_id], R[high_id]), Circle(P[low_id], R[low_id]), a, b)){if ((a.x + b.x) * 0.5 < mid){Right = mid;}else Left = mid;}else return false;}return false;}void circle_center(Point p0, Point p1, Point p2, Point &cp){double a1 = p1.x - p0.x, b1 = p1.y - p0.y, c1 = (a1 * a1 + b1 * b1) / 2;double a2 = p2.x - p0.x, b2 = p2.y - p0.y, c2 = (a2 * a2 + b2 * b2) / 2;double d = a1 * b2 - a2 * b1;cp.x = p0.x + (c1 * b2 - c2 * b1) / d;cp.y = p0.y + (a1 * c2 - a2 * c1) / d;}void circle_center(Point p0, Point p1, Point &cp){cp.x = (p0.x + p1.x) / 2;cp.y = (p0.y + p1.y) / 2;}Point center;double radius;bool Point_in(const Point &p){return Distance(p, center) - radius < 0;}void min_circle_cover(Point a[], int n){radius = 0;center = a[0];for (int i = 1; i < n; i++)if (!Point_in(a[i])){center = a[i];radius = 0;for (int j = 0; j < i; j++)if (!Point_in(a[j])){circle_center(a[i], a[j], center);radius = Distance(a[j], center);for (int k = 0; k < j; k++)if (!Point_in(a[k])){circle_center(a[i], a[j], a[k], center);radius = Distance(a[k], center);}}}}int main(int argc, char const *argv[]){while (~scanf("%lf%lf%lf", &p0.x, &p0.y, &d)){scanf("%d",  &n);for (int i = 0; i < n; i++){R[i] = d;scanf("%lf%lf", &P[i].x, &P[i].y);}P[n] = p0; min_circle_cover(P, n);double Left = 0, Right = Distance(center, p0) + eps, mid;int ok = 0;while (dcmp(Right - Left) > 0){mid = (Left + Right) / 2;R[n] = mid;if (Judge(mid)) Right = mid, ok = 1;else Left = mid;}if (ok) printf("%.2lf\n", mid);else cout << "X" << endl;}return 0;}


一看题目,显然是二分,二分枚举到房子的距离也就是路由器到房子的距离,确定最大值应该用模拟退火,退火时间复杂度O(n)。


比网上的O(n3)的暴力高得不知道到哪去了,暴力普遍需要2K毫秒,这个只要78毫秒就可以了。哈哈哈。

0 0
原创粉丝点击