poj 3384 Feng Shui(半平面交)

本文介绍了一种解决特定几何问题的方法,通过将边内推一定距离并求半平面交集,进而找到凸多边形上的最远点对。该方法适用于如POJ 3525等类型的问题,并提供了一个具体的C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

思路:将边内推r后求半平面交,然后再在所得的凸多边形上寻找最远点对
在做poj 3525的时候也要把边内推一定距离,但是做那个题的方法放到这个题里,老是wa,我猜可能是误差问题,但是测试样例过了。。。就看了看别人题解里内推r的办法,然后ac了

#include <iostream>
#include <algorithm>
#include <cmath>
#include <iomanip>
using namespace std;

struct Point
{
    double x,y;
    Point() {}
    Point(double _x,double _y)
    {
        x = _x;
        y = _y;
    }
    Point operator -(const Point &b)const
    {
        return Point(x - b.x, y - b.y);
    }
    double operator ^(const Point &b)const
    {
        return x*b.y - y*b.x;
    }
    double operator *(const Point &b)const
    {
        return x*b.x + y*b.y;
    }
};
const int MAXN = 110;
const double eps = 1e-10;
int n,m;
double r;
Point p[MAXN];
Point np[MAXN];
Point tp[MAXN];
Point res1,res2;

void Get_equation(Point p1,Point p2,double &a,double &b,double &c)
{
    a = p2.y - p1.y;
    b = p1.x - p2.x;
    c = p2.x*p1.y - p1.x*p2.y;
}

Point Intersection(Point p1,Point p2,double a,double b,double c)
{
    double u = fabs(a*p1.x + b*p1.y + c);
    double v = fabs(a*p2.x + b*p2.y + c);
    Point t;
    t.x = (p1.x*v + p2.x*u)/(u+v);
    t.y = (p1.y*v + p2.y*u)/(u+v);
    return t;
}

void Cut(double a,double b,double c)
{
    int tmp = 0;
    for(int i = 1; i <= m; i++)
    {
        if(a*np[i].x + b*np[i].y + c >= 0)
            tp[++tmp] = np[i];
        else
        {
            if(a*np[i-1].x + b*np[i-1].y + c > 0)
                tp[++tmp] = Intersection(np[i-1],np[i],a,b,c);
            if(a*np[i+1].x + b*np[i+1].y + c > 0)
                tp[++tmp] = Intersection(np[i],np[i+1],a,b,c);
        }
    }
    for(int i = 1; i <= tmp; i++)
        np[i] = tp[i];
    np[0] = np[tmp];
    np[tmp+1] = np[1];
    m = tmp;
}

double dist2(Point a, Point b)
{
    return (a-b)*(a-b);
}

void solve()
{
    Point p1,p2,p3;
    double a,b,c;
    for(int i = 1; i <= n; ++i)
        np[i] = p[i];
    p[n+1] = p[1];
    np[0] = np[n];
    np[n+1] = np[1];
    m = n;
    for(int i = 1; i <= n; ++i)
    {
        p1.y = p[i].x - p[i+1].x;
        p1.x = p[i+1].y - p[i].y;
        double k = r/sqrt(p1.x*p1.x+p1.y*p1.y);
        p1.x *= k;
        p1.y *= k;
        p2.x = p[i].x + p1.x;
        p2.y = p[i].y + p1.y;
        p3.x = p[i+1].x + p1.x;
        p3.y = p[i+1].y + p1.y;
        Get_equation(p2,p3,a,b,c);
        Cut(a,b,c);
    }

    double dis = 0,ans = -99999999;
    for(int i = 1; i <= m; ++i)
    {
        for(int j = i; j <= m; ++j)
        {
            dis = dist2(np[i],np[j]);
            if(dis > ans)
            {
                ans = dis;
                res1 = np[i];
                res2 = np[j];
            }
        }
    }
}

int main()
{
    while(cin >> n >> r)
    {
        for(int i = 1; i <= n; ++i)
            cin >> p[i].x >> p[i].y;
        solve();
        cout << fixed << setprecision(4) << res1.x << " " << res1.y << " " << res2.x << " " << res2.y << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值