pku 1039 Pipe 叉积的应用
http://poj.org/problem?id=1039
黑书上的一道题目:
题意:有一宽度为1的折线管道,上面顶点为(xi,yi),所对应的下面顶点为(xi,yi-1),假设管道都是不透明的,不反射的,光线从左边入口处的(x0,y0),(x,y0-1)之间射入,向四面八方传播,求解光线最远能传播到哪里(取x坐标)或者是否能穿透整个管道.
如果一根光线自始至终都未擦到任何顶点,那么它肯定不是最优的,因为可以通过平移来使之优化,如果只碰到一个顶点,那也不是最优的,可以通过旋转,使它碰到另一个顶点,并且更优,即最优光线一定擦到一个上顶点和一个下顶点.
这样枚举所有的上下两个转折点形成线段,然后从0到n枚举所有转折点如果与之相交则满足,直到找到不想交的然后计算x,找出最大的x即可。
#include <cstdio> #include <cstring> #include <iostream> #define maxn 21 using namespace std; const double eps = 1e-8; struct point { double x,y; }up[maxn],down[maxn]; int n; int dblcmp(double x) { if (x > eps) return 1; else if (x < -eps) return -1; else return 0; } double det(double x1,double y1,double x2,double y2) { return x1*y2 - x2*y1; } double cross(point a,point b,point c) { return det(b.x - a.x,b.y - a.y,c.x - a.x,c.y - a.y); } double getx(point a,point b,point c,point d) { double k1,k2,b1,b2; k1 = (b.y - a.y)/(b.x - a.x); k2 = (d.y - c.y)/(d.x - c.x); b1 = a.y - k1*a.x; b2 = d.y - k2*d.x; return (b2 - b1)/(k1 - k2); } void solve() { int i,j,k; double ans = -10000000.0; for (i = 0; i < n; ++i) { for (j = 0; j < n; ++j) { if (i == j) continue;//同一个转折点上下就不用了 //寻找不想交的 for (k = 0; k < n; ++k) { if (dblcmp(cross(up[i],down[j],up[k]))*dblcmp(cross(up[i],down[j],down[k])) > 0) break; } double temp = 0; //计算x,并求出最大 if (k < max(i,j)) continue; temp = getx(up[i],down[j],up[k],up[k - 1]); if (temp > ans) ans = temp; temp = getx(up[i],down[j],down[k],down[k - 1]); if (temp > ans) ans = temp; if (k >= n) { printf("Through all the pipe.\n"); return ; } } } printf("%.2lf\n",ans); } int main() { int i; while (~scanf("%d",&n)) { if (!n) break; 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.0; } solve(); } return 0; }