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

pro:给定一个N边形,然后给半径为R的圆,问是否可以放进去。  问题转化为多边形的最大内接圆半径。(N<50);

sol:乍一看,不就是二分+半平面交验证是否有核的板子题吗。 然而事情并没有那么简单。  因为我们的多边形可能是凹多边形,而前面的方法只对凸多边形有效。

学习了下模拟退火的算法,这个随机算法只在最小圆覆盖的时候写过。 这里再学一下,看起来更正宗一点的。  每次在当前点的附近(R)找是否能优化,而这个R慢慢变小,使得趋紧答案的趋势更精细。

判定点再多边形内:同样,不能用检验是否在每条边的左边来判定,因为不是凸多边形; 我们可以用射线法搞。

(rate和次数是抄的别人的,我自己也不会分析。 感觉这个取决于数据和人品吧

(随机要加srand来增加随机性。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=110;
const double pi=acos(-1.0);
const double inf=0x7fffffff;
struct point {
    double x,y;
    point(){}
    point(double xx,double yy):x(xx),y(yy){}
};
struct line{
    point s,p;
    line(){}
    line(point xx,point yy):s(xx),p(yy){}
};
double getdis(point w,point v){
    return sqrt((w.x-v.x)*(w.x-v.x)+(w.y-v.y)*(w.y-v.y));
}
point operator /(point a,double t){ return point(a.x/t,a.y/t);}
point operator *(point a,double t){ return point(t*a.x,t*a.y);}
point operator -(point w,point v){return point(w.x-v.x,w.y-v.y);}
point operator +(point w,point v){return point(w.x+v.x,w.y+v.y);}
double det(point w,point v){ return w.x*v.y-w.y*v.x;}
double dot(point w,point v){ return w.x*v.x+w.y*v.y;}
double ltoseg(point p,point a,point b){
    point t=p-a;
    if(dot(t,b-a)<=0) return getdis(p,a);
    else if(dot(p-b,a-b)<=0) return getdis(p,b);
    return fabs(det(t,b-a))/getdis(a,b);
}
point p[maxn],tp[maxn]; double dist[maxn]; int N; line L[maxn];
bool isinside(point a)
{
//算法描述:首先,对于多边形的水平边不做考虑,其次,
//对于多边形的顶点和射线相交的情况,如果该顶点时其所属的边上纵坐标较大的顶点,则计数,否则忽略该点,
//最后,对于Q在多边形上的情形,直接判断Q是否属于多边形。
    int ncross=0;
    rep(i,0,N-1) {
        point p1=p[i],p2=p[i+1];
        if(ltoseg(a,p[i],p[i+1])==0) return true; //在线段上
        if(p1.y==p2.y) continue; //默认做水平x轴的线,所以水平线不考虑
        if(a.y<min(p1.y,p2.y)) continue; //相离不考虑
        if(a.y>max(p1.y,p2.y)) continue;
        double t=det(a-p[i],a-p[i+1]);
        if((t>=0&&p[i].y<a.y&&p[i+1].y>=a.y)||(t<=0&&p[i+1].y<a.y&&p[i].y>=a.y)) ncross++;
    }
    return (ncross&1);
}
double getmindis(point a)
{
    double ans=inf;
    rep(i,0,N-1) ans=min(ans,ltoseg(a,p[i],p[i+1]));
    return ans;
}
int main()
{
    srand(unsigned(time(NULL)));
    while(~scanf("%d",&N)&&N){
        double X,Y,R; X=Y=0;
        rep(i,1,N) {
            scanf("%lf%lf",&p[i].x,&p[i].y);
            X=max(X,p[i].x);
            Y=max(Y,p[i].y);
        }
        p[0]=p[N];
        rep(i,0,N-1) L[i]=line(p[i],p[i+1]-p[i]);
        scanf("%lf",&R);
        int maxt=min(N,20);
        rep(i,0,maxt-1){
            tp[i]=(p[i]+p[i+1])/2;
            dist[i]=0;
        }
        double step=min(X,Y);
        const int maxd=10;
        const double rate=0.55;
        bool flag=0;
        const double EPS2=1e-6;
        while(step>EPS2&&!flag){
            rep(i,0,maxt-1){
                rep(j,0,maxd-1){
                    double d=rand()%360/360.0*2*pi;
                    point next=tp[i];
                    next.x+=step*sin(d);
                    next.y+=step*cos(d);
                    if(!isinside(next)) continue;
                    double tdis=getmindis(next);
                    if(tdis+EPS2>dist[i]){
                        dist[i]=tdis; tp[i]=next;
                    }
                    if(tdis+EPS2>=R){
                        flag=1; break;
                    }
                }
            }
            step*=rate;
        }
        if(flag) puts("Yes");
        else puts("No");
    }
    return 0;
}

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

原文地址:https://www.cnblogs.com/hua-dong/p/10991200.html

时间: 2024-11-18 05:40:21

HDU - 3644:A Chocolate Manufacturer's Problem(模拟退火, 求多边形内最大圆半径)的相关文章

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

题意:判断简单多边形内是否可以放一个半径为R的圆 思路:如果这个多边形是正多边形,令r(x,y)为圆心在(x,y)处多边形内最大圆的半径,不难发现,f(x,y)越靠近正多边形的中心,r越大,所以可以利用模拟退火法来逼近最优点.对于一般的多边形,由于可能存在多个这样的"局部最优点",所以可以选不同的点作为起点进行多若干次模拟退火即可. 模拟退火的过程:每次由原状态S生成一个新状态T,如果T比S优,那么接受这一次转移,否则以一定概率P接受这次转移,因为这样可能会跳过局部最优解而得到全局最优

Hdu 4458 Shoot the Airplane(判断点在多边形内)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=4458 思路:以飞机为参考系,则飞机相对静止,子弹加上水平方向速度-v.则只需枚举时间,判断该时间时点(子弹)是否在多边形(飞机)内.注意g可以为0,分匀变速和匀速.另外本题精度要求较高,判断点在线段上用坐标差值,避免使用Dot . #include<cstdio> #include<cstring> #include<iostream> #include<algori

HDU 3644 模拟退火

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3644 题意:给定n个点的一个多边形,一个圆的半径,判断圆是否可以放在多边形里, 由于圆形坐标没确定,所以采用模拟退火法来算,不断地减小步长,选取n个点,点在多边形内采用穿线法判断, 精度很坑爹,调了一下午精度,在wa与tle之间徘徊20+次,吐血AC. 代码: /* *********************************************** Author :rabbit Crea

HDU 3644

模拟退火算法.... 这道题,呃.我怎么感觉他就是随机的.同一个代码,时而AC,时而WA.其实还真的是随机的.呵呵呵呵呵...因为下降火太快了,没办法,而降得慢又会...TLE,虽然精度提高了. 敢问,还有什么好的方法?我是在做退火算法时遇到这个练手的. #include <iostream> #include <cmath> #include <cstdio> #include <algorithm> #include <cstring> #i

hdu 4975 A simple Gaussian elimination problem.(网络流,判断矩阵是否存在)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4975 Problem Description Dragon is studying math. One day, he drew a table with several rows and columns, randomly wrote numbers on each elements of the table. Then he counted the sum of each row and col

HDU 4972 A simple dynamic programming problem(推理)

HDU 4972 A simple dynamic programming problem 题目链接 推理,会发现只有前一个和当前一个分数为(1, 2)或(2, 1)的时候,会有两种加分方法,其他情况最多就一种情况,所以只要统计(1, 2),(2, 1)的个数,最后判断分差是否为0,如果不为0,那么可能是正或负,那就是两倍 代码: #include <cstdio> #include <cstring> const int N = 100005; int t, n, a[N]; i

HDU 4971 A simple brute force problem.(dp)

HDU 4971 A simple brute force problem. 题目链接 官方题解写的正解是最大闭合权,但是比赛的时候用状态压缩的dp也过掉了- -,还跑得挺快 思路:先利用dfs预处理出每个项目要完成的技术集合,那么dp[i][j]表示第i个项目,已经完成了j集合的技术,由于j这维很大,所以利用map去开数组 代码: #include <cstdio> #include <cstring> #include <algorithm> #include &l

hdu 4972 A simple dynamic programming problem(高效)

题目链接:hdu 4972 A simple dynamic programming problem 题目大意:两支球队进行篮球比赛,每进一次球后更新比分牌,比分牌的计数方法是记录两队比分差的绝对值,每次进球的分可能是1,2,3分.给定比赛中的计分情况,问说最后比分有多少种情况. 解题思路:分类讨论: 相邻计分为1-2或者2-1的时候,会对应有两种的的分情况 相邻计分之差大于3或者说相等并且不等于1的话,为非法输入 其他情况下,不会造成新的比分情况产生 对于最后一次比分差为0的情况,就没有谁赢谁

【最小割】HDU 4971 A simple brute force problem.

说是最大权闭合图.... 比赛时没敢写.... 题意 一共有n个任务,m个技术 完成一个任务可盈利一些钱,学习一个技术要花费钱 完成某个任务前需要先学习某几个技术 但是可能在学习一个任务前需要学习另几个任务 求最多能赚多少钱咯 先将缩点将需要一起学掉的技术缩成一个点 建s--任务 权值为该任务盈利多少钱 建技术(缩点后)-t 权值为学习这技术的花费(总) 任务-技术 (完成该任务所需的每个技术都需要建边)权值为INF #include<stdio.h> #include<stdlib.h