poj1039

题意:几何计算,给出一个管道(一条从左到右的折线,与它向下移动1后的折线构成),问管道最左边发出的光线所能到达的最远位置的横坐标是多少。

分析:容易知道,要求一个能到达最远的光线,这条光线一定是经过至少两个折线的折点(每个这点可能是上面折线的,也可能是下面折线的),那么我们就每次枚举两个管道折点,求一直线看该直线与管道边缘线段交点。在求的过程中,可以从左到右依次判断是否与各个折点的横断面相交,然后可以得知是否会与管道壁相交。通过直线在横断面对应横坐标的位置的纵坐标高于还是低于横断面。可以判断其与那个管道壁相交,求交点即可。然后在所有交点中找一个横坐标最小的。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
#include
<cmath>
usingnamespace std;

#define maxn 25
#define eps 1.0e-8

struct Point
{
double x, y;
} point[maxn];

int n;
double ans;
bool ok;

void input()
{
for (int i =0; i < n; i++)
scanf(
"%lf%lf", &point[i].x, &point[i].y);
}

double intersect(Point a1, Point b1, Point a2, Point b2)
{
double x1 = a1.x, x2 = b1.x, x3 = a2.x, x4 = b2.x;
double y1 = a1.y, y2 = b1.y, y3 = a2.y, y4 = b2.y;
double x =(y3-y1+x1*(y2-y1)/(x2-x1)-x3*(y4-y3)/(x4-x3))/((y2-y1)/(x2-x1)-(y4-y3)/(x4-x3));
return x;
}

void work(Point a, Point b)
{
b.y
-=1;
for (int i =0; i < n; i++)
{
Point p, q1, q2;
p.x
= point[i].x;
p.y
= a.y - (b.y - a.y) / (b.x - a.x) * (a.x - p.x);
if ((p.y + eps < point[i].y && p.y - eps > point[i].y -1) || abs(p.y
- point[i].y) < eps || abs(p.y - point[i].y +1) < eps)
continue;
if (i ==0)
return;
if (p.y - eps > point[i].y)
ans
= max(ans, intersect(a, b, point[i -1], point[i]));
else
{
q1
= point[i -1];
q1.y
-=1;
q2
= point[i];
q2.y
-=1;
ans
= max(ans, intersect(a, b, q1, q2));
}
return;
}
ok
=true;
}

int main()
{
//freopen("t.txt", "r", stdin);
while (scanf("%d", &n), n)
{
input();
ans
= point[0].x;
ok
=false;
for (int i =0; i < n; i++)
for (int j =0; j < n; j++)
if (i != j &&!ok)
work(point[i], point[j]);
if (ok)
printf(
"Through all the pipe.\n");
else
printf(
"%.2f\n", ans);
}
return0;
}
原文地址:https://www.cnblogs.com/rainydays/p/2096818.html