poj1039 Pipe (计算几何)

我的第一个计算几何的题目

题意:给出一个曲折的管道,求出光线能够到达的管道的最远点的横坐标。

思路:能够到达最远点的直线必然通过管道的一个上管道壁的折点和一个下管道壁的折点,枚举所有的这样的折点,求出最远能够到达的地方的横坐标。


计算几何基础知识参见lrj黑书。

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

//点定义
struct Point {
   double x, y;
} up[22], down[22];

//精度
const double eps = 1e-3;

double Max(double a, double b) {
  return a > b ? a : b;
}

double Min(double a, double b) {
  return a > b ? b : a;
}

/*若返回值大于0,则射线p0p1在射线p0p2顺时针方向; 
   若返回值小于0,则射线p0p1在射线p0p2逆时针方向;
   若返回值等于0,则p0p1和p0p2共线,方向可能相同,也可能相反*/
double Multi(Point p1, Point p2, Point p0) {
   return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}

//与lrj书不同,书上是判断两线段是否严格相交,此处是判断直线ab与线段cd是否相交,cd的端点在ab上也算相交
bool Across(Point a, Point b, Point c, Point d) {
    double tmp = Multi(c, b, a) * Multi(d, b, a);
    if (tmp < 0 || fabs(tmp) < eps) return true;
    return false;
}

/*求直线 l1; A1*x + B1*y + C1 = 0 与直线 l2: A2*x + B2*y + C2 = 0 的交点,此处只返回交点横坐标x
   a,b为直线 l1 上的两点, c , d为直线 l2 上的两点 */
double getIntersect(Point a, Point b, Point c, Point d) {
    double A1 = b.y - a.y;
    double B1 = a.x - b.x;
    double C1 = (b.x - a.x) * a.y - (b.y - a.y) * a.x;
    double A2 = d.y - c.y;
    double B2 = c.x - d.x;
    double C2 = (d.x - c.x) * c.y - (d.y - c.y) * c.x;
    double x = (C2 * B1 - C1 * B2) / (A1 * B2 - A2 * B1);
    //y = (C1 * A2 - C2 * A1) / (A1 * B2 - A2 * B1); //交点纵坐标    
    return x;
 }

int main() {
    int n, i, j, k;
    double best;
    bool flag;

    while (scanf ("%d", &n) && n) {
         for (i = 0; i < n; i++) {
            scanf ("%lf%lf", &up[i].x, &up[i].y);
            down[i].x = up[i].x;
            down[i].y = up[i].y - 1;
         }
         best = up[0].x;
         flag = false;
         for (i = 0; i < n && !flag; i++) {
            for (j = 0; j < n && !flag; j++) {
                if (i != j) {
                   for (k = 0; k < n; k++)
                      if (!Across(up[i], down[j], up[k], down[k])) break;
                   if (k == n) flag = true;
                   else if (k > Max(i, j)) {
                      double tmp;
                      tmp = getIntersect(up[i], down[j], up[k-1], up[k]);
                      if (tmp > best) best = tmp;
                      tmp = getIntersect(up[i], down[j], down[k-1], down[k]);
                      if (tmp > best) best = tmp;
                   }
                }
            }
         }
         if (flag) printf ("Through all the pipe.\n");
         else printf ("%.2lf\n", best);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值