poj 1584

题目概述

给定一任意多边形的定点数N及每个顶点的坐标x,y,一个圆的圆心坐标X,Y及其半径R,问多边形是否为凸多边形,若是,则求圆是否被多边形包含
圆与多边形的边相切视为圆在多边形内部
多边形的顶点会按顺时针或逆时针给出

时限

1000ms/3000ms

输入

第一行一个正整数N,三个浮点数R,X,Y,其后N行,每行两个浮点数x,y,输入到N<3为止(因为这不是多边形)

限制

没有限制

输出

每行一个字符串,若多边形为凹,则为
HOLE IS ILL-FORMED
若多边形为凸但圆不被多边形包含,则为
PEG WILL NOT FIT
若多边形为凸且圆可被多边形包含,则为
PEG WILL FIT

样例输入

5 1.5 1.5 2.0
1.0 1.0
2.0 2.0
1.75 2.0
1.0 3.0
0.0 2.0
5 1.5 1.5 2.0
1.0 1.0
2.0 2.0
1.75 2.5
1.0 3.0
0.0 2.0
3 0.1 0.2 0.0
-0.5 1.0
0.5 -1.0
0.5 1.0
3 0.25 0.2 0.0
-0.5 1.0
0.5 -1.0
0.5 1.0
3 0.1 1.6 1.2
1.0 1.0
2.0 1.0
1.0 2.0
6 0.1 1.6 1.2
1.0 1.0
1.5 1.0
2.0 1.0
1.2 1.8
1.0 2.0
1.0 1.5
3 0.1 2.0 2.0
1.0 1.0
2.0 1.0
1.0 2.0
4 1.0 2.0 1.0
0.0 0.0
0.0 4.0
4.0 4.0
4.0 0.0
4 1.0 3.5 1.0
0.0 0.0
0.0 4.0
4.0 4.0
4.0 0.0
4 0.2 1.5 1.0
1.0 1.0
2.0 2.0
1.0 3.0
0.0 2.0
4 0.4 1.5 1.0
1.0 1.0
2.0 2.0
1.0 3.0
0.0 2.0
5 0.2 1.5 2.5
1.0 1.0
2.0 2.0
1.75 2.75
1.0 3.0
0.0 2.0
5 0.2 1.5 2.5
1.0 1.0
2.0 2.0
1.75 2.5
1.0 3.0
0.0 2.0
9 0.2 0.5 2.5
0.0 0.0
1.0 0.0
1.0 1.0
2.0 1.0
2.0 0.0
3.0 0.0
3.0 5.0
1.5 5.0
0.0 5.0
9 0.2 0.5 2.5
0.0 0.0
1.0 0.0
1.0 -1.0
2.0 -1.0
2.0 0.0
3.0 0.0
3.0 5.0
1.5 5.0
0.0 5.0
7 0.2 0.5 2.5
0.0 0.0
1.0 0.0
2.0 0.0
3.0 0.0
3.0 5.0
1.5 5.0
0.0 5.0
1

样例输出

HOLE IS ILL-FORMED
PEG WILL NOT FIT
PEG WILL FIT
PEG WILL NOT FIT
PEG WILL FIT
PEG WILL FIT
PEG WILL NOT FIT
PEG WILL FIT
PEG WILL NOT FIT
PEG WILL NOT FIT
PEG WILL NOT FIT
PEG WILL FIT
PEG WILL NOT FIT
HOLE IS ILL-FORMED
HOLE IS ILL-FORMED
PEG WILL FIT

讨论

计算几何,同时考察判断多边形凹凸性,圆与多边形位置关系(包含点与多边形位置关系,点到线段最短距离),对于凹凸性判断,可以参考hdu 2108,不过那个题给出点的顺序是已知的,需要一点改进,对于位置关系,首先利用向量积判断圆心是否在多边形内,若在其内,则应当在所有边的同一侧,但是同样需要(相同的)一点改进,对于判断点到线段最短距离,过圆心做线段所在直线的垂线,求垂足,没有斜率的两种情况仍然需要特殊处理,依旧是利用点斜式方程组,只是注意垂直的两条线的斜率积是-1,求得垂足后,由于垂足必然和线段共线,利用快速排斥判断是否在线段上,若是,判断垂足到圆心距离是否小于半径,若否,判断圆心到线段端点的两个距离的最小值是否小于半径
虽说一次给出这么多样例数据不是很地道,但是如果一时半会解不出来最后总得要找数据,不过实际评测的数据比这个还要复杂(因为额在样例全过的情况下仍然能贡献WA)
代码的冗余度仍然是很大,其实可以把除了输入以外所有的for循环合成为一个,不过会很不直观(其实现在这样也很不直观)
另外题目没说数据规模是多少,额将就猜的1000

题解状态

200K,0MS,C++,2390B

题解代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define INF 0x3f3f3f3f  
#define MAXN 1003
#define memset0(a) memset(a,0,sizeof(a))
#define EPS 1e-6

int N;//多边形顶点数
double R, X, Y;//圆半径 圆心坐标
double x[MAXN], y[MAXN];//多边形顶点坐标
int signal(double a)//符号函数 所有判断正负用这个就不会纠结浮点误差了
{
    if (abs(a) < EPS)
        return 0;
    else if (a > 0)
        return 1;
    else
        return -1;
}
double xp(double x1, double y1, double x2, double y2, double x3, double y3)//老熟人向量积
{
    return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2);
}
double dis(double x1, double y1, double x2, double y2)//distance 两点间距离
{
    return sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
}
bool onsegment(double x, double y, double x1, double y1, double x2, double y2)//另一个老熟人快速排斥
{
    return min(x1, x2) <= x&&x <= max(x1, x2) && min(y1, y2) <= y&&y <= max(y1, y2);
}
void point_of_intersection(double x0, double y0, double x1, double y1, double x2, double y2, double &poix, double &poiy)//过直线外一点做垂线 求垂足坐标 点0是直线外的点(即圆心) 点poi用于返回垂足坐标 全称参考函数名
{
    if (!signal(y1 - y2))
        poix = x0, poiy = y1;
    else if (!signal(x1 - x2))//两种没有斜率的情况
        poiy = y0, poix = x1;
    else {
        double k1 = (y2 - y1) / (x2 - x1);//直线斜率
        double k0 = -1 / k1;//垂线斜率
        poix = (y1 - y0 - k1*x1 + k0*x0) / (k0 - k1);
        poiy = (x0 - x1 - k0*y1 + k1*y0) / (k1 - k0);//利用点斜式方程组求得
    }
}
void fun()
{
    scanf("%lf%lf%lf", &R, &X, &Y);//input
    for (int p = 0; p < N; p++)
        scanf("%lf%lf", &x[p], &y[p]);//input
    int sgn1 = signal(xp(x[2], y[2], x[0], y[0], x[1], y[1]));//signal 初始化前三个点的向量积符号 因为题目给定顶点坐标的顺序是不定的 只能用同号(而非正负)判断在同一方向 多边形一定有这三个点 下面的for判断凹凸性
    for (int p = 1; p < N; p++) {//第一组已经在上面用过了 略过
        int sgn2 = signal(xp(x[(p + 2) % N], y[(p + 2) % N], x[p], y[p], x[(p + 1) % N], y[(p + 1) % N]));//计算向量积符号 取模使循环一圈后不出错
        if (sgn1*sgn2 < 0) {//如果前后两次向量积是异号的 放到graham's scan算法中是会退栈的情况
            printf("HOLE IS ILL-FORMED\n");//output//凹的
            return;
        }
        sgn1 = sgn2;//更新符号值
    }
    sgn1 = signal(xp(X, Y, x[0], y[0], x[1], y[1]));//初始化圆心和前两个点的向量积符号 下面的for判断圆心和多边形位置关系
    for (int p = 1; p < N; p++) {//第一组略过
        int sgn2 = signal(xp(X, Y, x[p], y[p], x[(p + 1) % N], y[(p + 1) % N]));
        if (sgn1*sgn2 < 0) {//思路和上面几乎一致
            printf("PEG WILL NOT FIT\n");//output//圆心都在外面 何谈包含
            return;
        }
        sgn1 = sgn2;//更新符号值
    }
    for (int p = 0; p < N; p++) {//这个for判断圆心到线段距离是否小于半径
        double poix, poiy;//point_of_intersection 交点(垂足)坐标
        point_of_intersection(X, Y, x[p], y[p], x[(p + 1) % N], y[(p + 1) % N], poix, poiy);
        if (onsegment(poix, poiy, x[p], y[p], x[(p + 1) % N], y[(p + 1) % N]) && dis(poix, poiy, X, Y) < R) {//如果垂足在线段上且距离小于半径 实际上若拆成两条if语句可以避免下面else if的多余运算
            printf("PEG WILL NOT FIT\n");//output//多边形(的一条边)和圆相交了
            return;
        }
        else if (min(dis(X, Y, x[p], y[p]), dis(X, Y, x[(p + 1) % N], y[(p + 1) % N])) < R) {//垂足不在线段上 但圆心到端点的距离最小值小于半径 如果距离最近的垂足都比半径远而没返回 那距离更远的端点就更不用提了
            printf("PEG WILL NOT FIT\n");//output
            return;
        }
    }
    printf("PEG WILL FIT\n");//output
}
int main(void)
{
    //freopen("vs_cin.txt", "r", stdin);
    //freopen("vs_cout.txt", "w", stdout);

    while (~scanf("%d", &N) && N > 2) {//input
        fun();
    }
}

EOF

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值