POJ 1039 Pipe【计算几何+直线相交】

题目链接

题意:有一根管子,从管口射进去一根光线,问最远能到的点的横坐标。

枚举上下两个端点。先判断经过这两个端点的光线是否能和管口相交,再计算这根光线所能达到的最远的点。

要注意的地方:
1. 求的是横坐标,不是距离
2. 坐标可能会有负,ans初始化为-INF
3. 注意精度问题

卡精度WA了好久,好气啊……

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <map>
using namespace std;
typedef long long ll;

const double eps=1e-8;
const int maxn=30;
const ll INF=0x3f3f3f3f3f;

struct Point{
    double x,y;
    Point(){}
    Point(double a,double b){
        x=a,y=b;
    }
};

int n;
Point point_up[maxn],point_down[maxn];

Point interSectionPoint(Point p1,Point p2,Point p3,Point p4){
    Point ret=p1; 
    double t=((p1.x-p3.x)*(p3.y-p4.y)-(p1.y-p3.y)*(p3.x-p4.x))
    /((p1.x-p2.x)*(p3.y-p4.y)-(p1.y-p2.y)*(p3.x-p4.x));
    ret.x+=(p2.x-p1.x)*t; 
    ret.y+=(p2.y-p1.y)*t;
    return ret;
}

double dist(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool cmp(Point a,Point b){
    return a.x<b.x;
}

int main(){
    while (~scanf("%d",&n)&&n){
        for (int i=1;i<=n;i++){
            scanf("%lf %lf",&point_up[i].x,&point_up[i].y);
        }
        sort(point_up+1,point_up+n+1,cmp);
        for (int i=1;i<=n;i++){
            point_down[i].x=point_up[i].x;
            point_down[i].y=point_up[i].y-1;
        } 
        Point tmp;
        double ans=-INF;
        bool flag=false;
        for (int i=1;i<=n;i++){
            for (int j=1;j<=n;j++){
                if (i==j)
                    continue;
                Point left,right;
                tmp=interSectionPoint(point_up[1],point_down[1],point_up[i],point_down[j]);
                if (tmp.y+eps<point_down[1].y||tmp.y-eps>point_up[1].y)
                    continue;
                left=tmp;
                for (int k=2;k<=n;k++){
                    tmp=interSectionPoint(point_up[k],point_down[k],point_up[i],point_down[j]);
                    if (tmp.y+eps<point_down[k].y){
                        right=interSectionPoint(point_down[k],point_down[k-1],point_up[i],point_down[j]);
                        break;
                    }
                    else if (tmp.y-eps>point_up[k].y){
                        right=interSectionPoint(point_up[k],point_up[k-1],point_up[i],point_down[j]);
                        break;
                    }
                    else if (k==n){
                        flag=true;
                    }
                }
                ans=max(ans,right.x);
            }
        }
        if (flag)
            printf("Through all the pipe.\n");
        else
            printf("%.2f\n",ans);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值