[hdu3644 A Chocolate Manufacturer's Problem]模拟退火,简单多边形内最大圆

题意:判断简单多边形内是否可以放一个半径为R的圆

思路:如果这个多边形是正多边形,令r(x,y)为圆心在(x,y)处多边形内最大圆的半径,不难发现,f(x,y)越靠近正多边形的中心,r越大,所以可以利用模拟退火法来逼近最优点。对于一般的多边形,由于可能存在多个这样的"局部最优点",所以可以选不同的点作为起点进行多若干次模拟退火即可。

模拟退火的过程:每次由原状态S生成一个新状态T,如果T比S优,那么接受这一次转移,否则以一定概率P接受这次转移,因为这样可能会跳过局部最优解而得到全局最优解。

PS:步长每次改变的系数一般设为0.8~0.9,eps不能设太高。

#pragma comment(linker, "/STACK:10240000")
#include <bits/stdc++.h>
using namespace std;

#define X                   first
#define Y                   second
#define pb                  push_back
#define mp                  make_pair
#define all(a)              (a).begin(), (a).end()
#define fillchar(a, x)      memset(a, x, sizeof(a))

typedef long long ll;
typedef pair<int, int> pii;

namespace Debug {
void print(){cout<<endl;}template<typename T>
void print(const T t){cout<<t<<endl;}template<typename F,typename...R>
void print(const F f,const R...r){cout<<f<<" ";print(r...);}template<typename T>
void print(T*p, T*q){int d=p<q?1:-1;while(p!=q){cout<<*p<<", ";p+=d;}cout<<endl;}
}
template<typename T>bool umax(T&a, const T&b){return b<=a?false:(a=b,true);}
template<typename T>bool umin(T&a, const T&b){return b>=a?false:(a=b,true);}
/* -------------------------------------------------------------------------------- */

const double eps = 1e-4;/** 设置比较精度 **/
struct Real {
    double x;
    double get() { return x; }
    int read() { return scanf("%lf", &x); }
    Real(const double &x) { this->x = x; }
    Real() {}
    Real abs() { return x > 0? x : -x; }

    Real operator + (const Real &that) const { return Real(x + that.x);}
    Real operator - (const Real &that) const { return Real(x - that.x);}
    Real operator * (const Real &that) const { return Real(x * that.x);}
    Real operator / (const Real &that) const { return Real(x / that.x);}
    Real operator - () const { return Real(-x); }

    Real operator += (const Real &that) { return Real(x += that.x); }
    Real operator -= (const Real &that) { return Real(x -= that.x); }
    Real operator *= (const Real &that) { return Real(x *= that.x); }
    Real operator /= (const Real &that) { return Real(x /= that.x); }

    bool operator < (const Real &that) const { return x - that.x <= -eps; }
    bool operator > (const Real &that) const { return x - that.x >= eps; }
    bool operator == (const Real &that) const { return x - that.x > -eps && x - that.x < eps; }
    bool operator <= (const Real &that) const { return x - that.x < eps; }
    bool operator >= (const Real &that) const { return x - that.x > -eps; }

    friend ostream& operator << (ostream &out, const Real &val) {
        out << val.x;
        return out;
    }
    friend istream& operator >> (istream &in, Real &val) {
        in >> val.x;
        return in;
    }
};

struct Point {
    Real x, y;
    int read() { return scanf("%lf%lf", &x.x, &y.x); }
    Point(const Real &x, const Real &y) { this->x = x; this->y = y; }
    Point() {}
    Point operator + (const Point &that) const { return Point(this->x + that.x, this->y + that.y); }
    Point operator - (const Point &that) const { return Point(this->x - that.x, this->y - that.y); }
    Real operator * (const Point &that) const { return x * that.x + y * that.y; }
    Point operator * (const Real &that) const { return Point(x * that, y * that); }
    Point operator += (const Point &that)  { return Point(this->x += that.x, this->y += that.y); }
    Point operator -= (const Point &that)  { return Point(this->x -= that.x, this->y -= that.y); }
    Point operator *= (const Real &that)  { return Point(x *= that, y *= that); }

    bool operator == (const Point &that) const { return x == that.x && y == that.y; }

    Real cross(const Point &that) const { return x * that.y - y * that.x; }
    Real dist() { return sqrt((x * x + y * y).get()); }
};
typedef Point Vector;

struct Segment {
    Point a, b;
    Segment(const Point &a, const Point &b) { this->a = a; this->b = b; }
    Segment() {}
    bool intersect(const Segment &that) const {
        Point c = that.a, d = that.b;
        Vector ab = b - a, cd = d - c, ac = c - a, ad = d - a, ca = a - c, cb = b - c;
        return ab.cross(ac) * ab.cross(ad) < 0 && cd.cross(ca) * cd.cross(cb) < 0;
    }
    Point getLineIntersection(const Segment &that) const {
        Vector u = a - that.a, v = b - a, w = that.b - that.a;
        Real t = w.cross(u) / v.cross(w);
        return a + v * t;
    }
    Real Distance(Point P) {
        Point A = a, B = b;
        if (A == B) return (P - A).dist();
        Vector v1 = B - A, v2 = P - A, v3 = P - B;
        if (v1 * v2 < 0) return v2.dist();
        if (v1 * v3 > 0) return v3.dist();
        return v1.cross(v2).abs() / v1.dist();
    }
};

const int maxn = 55;
double PI = acos(-1.0);

Point p[maxn];
int n;

Real getAngel(Point o, Point a, Point b) {
    a -= o;
    b -= o;
    Real ans = acos((a * b / a.dist() / b.dist()).get());
    return a.cross(b) <= 0? ans : -ans;
}

bool inPolygon(Point o) {
    Real total = 0;
    for (int i = 0; i < n; i ++) {
        total += getAngel(o, p[i], p[(i + 1) % n]);
    }
    return total.abs() > PI;
}

Real getR(Point o) {
    Real ans = 1e9;
    for (int i = 0; i < n; i ++) {
        Segment seg(p[i], p[(i + 1) % n]);
        umin(ans, seg.Distance(o));
    }
    return ans;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    //freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
    while (cin >> n, n) {
        p[0].read();
        Real maxx = p[0].x, minx = p[0].x, maxy = p[0].y, miny = p[0].y;
        for (int i = 1; i < n; i ++) {
            p[i].read();
            umax(maxx, p[i].x);
            umin(minx, p[i].x);
            umax(maxy, p[i].y);
            umin(miny, p[i].y);
        }
        Real R;
        R.read();
        Point a(minx, miny), b(maxx, maxy);
        bool ok = false;
        for (int i = 0; !ok && i < n; i ++) {
            Real deta = (b - a).dist() / 4;
            Point O = (p[i] + p[(i + 1) % n]) * 0.5;
            int cnt = 0;
            while (!ok && deta > 0 && cnt < 100) {
                for (int j = 0; ; j ++) {
                    double randnum = rand();
                    Point newp(O.x + deta * sin(randnum), O.y + deta * cos(randnum));
                    if (!inPolygon(newp)) continue;
                    Real buf = getR(newp);
                    if (buf > getR(O) || j > 4) { /** 这里考虑了概率因素 **/
                        if (buf >= R) ok = true;
                        O = newp;
                        break;
                    }
                }
                deta *= 0.8;
                cnt ++;
            }
        }
        puts(ok? "Yes" : "No");
    }

}

[hdu3644 A Chocolate Manufacturer's Problem]模拟退火,简单多边形内最大圆

时间: 2025-01-07 11:20:11

[hdu3644 A Chocolate Manufacturer's Problem]模拟退火,简单多边形内最大圆的相关文章

HDU - 3644:A Chocolate Manufacturer&#39;s Problem(模拟退火, 求多边形内最大圆半径)

pro:给定一个N边形,然后给半径为R的圆,问是否可以放进去.  问题转化为多边形的最大内接圆半径.(N<50): sol:乍一看,不就是二分+半平面交验证是否有核的板子题吗. 然而事情并没有那么简单.  因为我们的多边形可能是凹多边形,而前面的方法只对凸多边形有效. 学习了下模拟退火的算法,这个随机算法只在最小圆覆盖的时候写过. 这里再学一下,看起来更正宗一点的.  每次在当前点的附近(R)找是否能优化,而这个R慢慢变小,使得趋紧答案的趋势更精细. 判定点再多边形内:同样,不能用检验是否在每条

判断点是否在简单多边形内常用方法

一.射线判别法:适用于所有简单多边形 简单多边形是不相邻的边不相交的多边形.判定点p是否在多边形G内部,包括边界.对于任意多边形,可以采用射线法.对于给定的点向左做一条平行x轴的射线l,求出l与多边形G的交点个数,如果个数为奇数则点在多边形内,如果交点个数为偶数则点在多边形外.具体可以归纳如下: 1.对G的水平边不做考虑 2.对l与G的顶点相交的情况,只考虑所属边纵坐标较大的顶点. 3.对于p在G边上的情况,直接判定p在G内 //0=outside ;1=inside;2=boundary in

【模板】计几 射线法判断点是否在简单多边形内

1 // 2 //线段交点个数 3 int SegCross(Segment a,Segment b){ 4 double x1 = a.s.cross(a.e,b.s); 5 double x2 = a.s.cross(a.e,b.e); 6 double x3 = b.s.cross(b.e,a.s); 7 double x4 = b.s.cross(b.e,a.e); 8 if( b.e.OnLine(a.s,a.e) && b.s.OnSeg(a.s,a.e) || 9 b.s.O

【转】[专题学习][计算几何]

原文地址:http://www.cnblogs.com/ch3656468/archive/2011/03/02/1969303.html 基本的叉积.点积和凸包等东西就不多说什么了,网上一搜一大堆,切一些题目基本熟悉了就差不多了. 一些基本的题目可以自己搜索,比如这个blog:http://blog.sina.com.cn/s/blog_49c5866c0100f3om.html 接下来,研究了半平面交,思想方法看07年朱泽园的国家队论文,模板代码参考自我校大牛韬哥: http://www.o

bzoj2965

http://www.lydsy.com/JudgeOnline/problem.php?id=2965 http://www.tsinsen.com/A1385 平面图网络流. 首先我们要将平面图转化成对偶图. 将每条无向边拆成两个向量,从一条未访问过的向量开始,找到逆时针方向上第一个向量,然后继续访问,直到形成环,这样就找到了一条轮廓线,且内部在向量的右边. 如图从为访问过的边1->8开始,找到8->7,然后继续找到7->1,形成了环,这样找到了一条轮廓线.内部在1->8,8-

temp、

1 #include <map> 2 #include <set> 3 #include <cmath> 4 #include <queue> 5 #include <stack> 6 #include <cstdio> 7 #include <string> 8 #include <vector> 9 #include <cstdlib> 10 #include <cstring> 1

21天学习caffe(一)

ubuntu环境安装caffe1 安装依赖 apt-get install libatlas-base-dev apt-get install python-dev apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev 等等等2 编译生成bin文件mv Makefile.config.example Makefile.config   #改名make or make -j2 排错:解决/boot空间不足问题 system mon

bzoj4948: World Final2017 A

求简单多边形内的最长线段长度 显然存在一组最优解,使其所在直线经过多边形的两个端点,枚举这两个端点,求出直线和多边形的有效交点,从而得出直线有哪些部分在多边形内(含边界). 由于多边形的一些边可能与直线重合,求交需要一些分类讨论. #include<bits/stdc++.h> typedef long long i64; typedef double ld; struct pos{ int x,y; ld abs(){return sqrt(i64(x)*x+i64(y)*y);} }ps[

poj-2420 A Star not a Tree?(模拟退火算法)

题目链接: A Star not a Tree? Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5219   Accepted: 2491 Description Luke wants to upgrade his home computer network from 10mbs to 100mbs. His existing network uses 10base2 (coaxial) cables that allo