链接 Pipe
题意
给出一个管道,问一道光能照射的最远距离的x坐标是多少;
思路
要想让光照射的更远,那么这束光一定经过一个上端点,一个下端点, 然后我们只需要去枚举上下端点即可;
对于上下端点构成的直线,对于每一个弯道都去判断上顶点和下顶点,(用叉积);
然后用点向式方程求最大的x即可;
AC代码
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#define x first
#define y second
using namespace std;
const long double eps = 1e-18;
const int N = 10010;
typedef long double LD;
typedef pair<LD, LD> PDD;
PDD operator -(PDD a, PDD b)
{
return make_pair(a.x - b.x, a.y - b.y);
}
int sign(double x)
{
if (fabs(x) < eps) return 0;
if (x < 0) return -1;
return 1;
}
LD cross(PDD a, PDD b)
{
return a.x * b.y - a.y * b.x;
}
//返回横坐标
LD get_intersect(PDD p, PDD v, PDD q, PDD w)
{
PDD u = p - q;
LD t = cross(w, u) / cross(v, w);
return p.x + v.x * t;
}
int n;
PDD up[N], down[N];
bool judge(int i, int j, int k)
{
return sign(cross(down[j] - up[i], up[k] - up[i])) * sign(cross(down[j] - up[i], down[k] - up[i])) <= 0;
}
void solve()
{
LD ans = -1e18;
for (int i = 1; i <= n; i ++)
{
for (int j = 1; j <= n; j ++)
{
if (i == j) continue;
int k = 1;
for (k = 1; k <= n; k ++) if (!judge(i, j, k)) break;
if (k > n)
{
puts("Through all the pipe.");
return ;
}
if (k < max(i, j)) continue;
LD res1 = get_intersect(up[i], down[j] - up[i], up[k], up[k - 1] - up[k]);
ans = max(ans, res1);
res1 = get_intersect(up[i], down[j] - up[i], down[k], down[k - 1] - down[k]);
ans = max(ans, res1);
}
}
printf("%.2lf\n", ans);
return;
}
int main()
{
while (cin >> n)
{
if (n == 0) break;
for (int i = 1; i <= n; i ++)
{
LD x, y;
cin >> x >> y;
up[i].x = x, up[i].y = y;
down[i].x = x, down[i].y = y - 1;
}
solve();
}
}