HDU 4455 Stealing a Cake(计算几何 点到圆 到矩形距离)

表示这个题目很坑,竟然普通的枚举角度也能过,在现场如果没敢这么干的童鞋肯定后悔死了,不过直接枚举跑的时间还是没三分枚举快的


三分枚举的思想其实和二分差不多,具体为什么对,看看代码是怎么枚举的,稍微想想就能明白了!


直接枚举:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define eps 1e-8
using namespace std;
#define PI acos(-1.0)
struct point
{
    double x;
    double y;
    point(double a=0,double b=0):x(a),y(b){}
}a,b,c,d,pos,temp1,temp2,start;
double r;
double cross(point p0, point p1, point p2)//j计算差乘
{   return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}
double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double disptoseg(point p,point l1,point l2)
{
    point t=p;
    t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;
    if(cross(l1,t,p)*cross(l2,t,p)>eps)
    return dis(p,l1) < dis(p,l2) ? dis(p,l1):dis(p,l2);
    return fabs(cross(p,l1,l2)/dis(l1,l2));
}
double distotri(point p)
{
    return min(disptoseg(p,a,b),min(disptoseg(p,b,d),min(disptoseg(p,d,c),disptoseg(p,c,a))));
}
point make_p(double l)
{
    return point(pos.x+r*cos(l),pos.y+r*sin(l));
}
double find_dis(point p)
{
    return dis(p,start)+distotri(p);
}
double find_ans()
{
double ans=1e10;
double mid=0;
double over=PI*2,k;
point p;
for(mid=0;mid<=over;mid+=1e-3)
{
    p=make_p(mid);
    k=find_dis(p);
    if(ans > k)
    ans=k;
}
return ans;
}
int main()
{
    while(scanf("%lf%lf",&start.x,&start.y))
    {
        if(start.x==0 && start.y==0)
        return 0;
        scanf("%lf%lf%lf",&pos.x,&pos.y,&r);
        scanf("%lf%lf%lf%lf",&temp1.x,&temp1.y,&temp2.x,&temp2.y);
        if(temp1.x > temp2.x)
        c=temp1,temp1=temp2,temp2=c;
        if(temp1.y > temp2.y)
        a=temp1,d=temp2,b.x=d.x,b.y=a.y,c.x=a.x,c.y=d.y;
        else
        c=temp1,b=temp2,a.x=c.x,a.y=b.y,d.x=b.x,d.y=c.y;
        printf("%.2lf\n",find_ans());
    }
    return 0;
}

三分枚举:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define eps 1e-8
using namespace std;
#define PI acos(-1.0)
struct point
{
    double x;
    double y;
    point(double a=0,double b=0):x(a),y(b){}
}a,b,c,d,pos,temp1,temp2,start;
double r;
double cross(point p0, point p1, point p2)//j计算差乘
{   return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);}
double dis(point a,point b)
{
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double disptoseg(point p,point l1,point l2)
{
    point t=p;
    t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;
    if(cross(l1,t,p)*cross(l2,t,p)>eps)
    return dis(p,l1) < dis(p,l2) ? dis(p,l1):dis(p,l2);
    return fabs(cross(p,l1,l2)/dis(l1,l2));
}
double distotri(point p)
{
    return min(disptoseg(p,a,b),min(disptoseg(p,b,d),min(disptoseg(p,d,c),disptoseg(p,c,a))));
}
point make_p(double l)
{
    return point(pos.x+r*cos(l),pos.y+r*sin(l));
}
double find_dis(point p)
{
    return dis(p,start)+distotri(p);
}
double find_ans()
{
double l,r,ans1,ans2,t_2,t_4;
l=0,r=PI;
double mid_2,mid_4;
point p_2,p_4;
while(r-l>=eps)
{
    mid_2=(l+r)/2;
    mid_4=(mid_2+r)/2;
    p_2=make_p(mid_2);
    p_4=make_p(mid_4);
    t_2=find_dis(p_2);
    t_4=find_dis(p_4);
    if(t_2 > t_4)
    l=mid_2;
    else
    r=mid_4;
}
p_2=make_p(l);
ans1=find_dis(p_2);
l=PI,r=PI*2;
while(r-l>=eps)
{
    mid_2=(l+r)/2;
    mid_4=(mid_2+r)/2;
    p_2=make_p(mid_2);
    p_4=make_p(mid_4);
    t_2=find_dis(p_2);
    t_4=find_dis(p_4);
    if(t_2 > t_4)
    l=mid_2;
    else
    r=mid_4;
}
p_2=make_p(l);
ans2=find_dis(p_2);
return min(ans1,ans2);
}
int main()
{
    while(scanf("%lf%lf",&start.x,&start.y))
    {
        if(start.x==0 && start.y==0)
        return 0;
        scanf("%lf%lf%lf",&pos.x,&pos.y,&r);
        scanf("%lf%lf%lf%lf",&temp1.x,&temp1.y,&temp2.x,&temp2.y);
        if(temp1.x > temp2.x)
        c=temp1,temp1=temp2,temp2=c;
        if(temp1.y > temp2.y)
        a=temp1,d=temp2,b.x=d.x,b.y=a.y,c.x=a.x,c.y=d.y;
        else
        c=temp1,b=temp2,a.x=c.x,a.y=b.y,d.x=b.x,d.y=c.y;
        printf("%.2lf\n",find_ans());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值