《算法艺术与信息学竞赛》p356例题,自己没做对,看了下题解,还是考虑的地方太少了。
题解:http://blog.csdn.net/lyy289065406/article/details/6648585
思路:
#include <cmath>
#include <cstring>
#include <cstdio>
struct Point
{
double x,y;
};
const double precision = 1e-8;
const double inf = 9999999.0;
Point upperPoint[25];
Point lowerPoint[25];
double res;
bool flag;
int n;
int max(int a, int b)
{
return a > b ? a : b;
}
int dblcmp(double d)//精度
{
if(fabs(d) < precision)
return 0;
return d < 0 ? -1 : 1;
}
double det(double x1, double y1, double x2, double y2)
{
return x1*y2 - x2*y1;
}
//求ab和ac叉积
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);
}
//如果ab和cd相交,返回true
bool check(Point a, Point b, Point c, Point d)
{
return dblcmp(cross(a,b,c))*dblcmp(cross(a,b,d)) <= 0;
}
double intersection(Point A, Point B, Point C, Point D)
{
double area1 = cross(A,B,C);
double area2 = cross(A,B,D);
int c = dblcmp(area1);
int d = dblcmp(area2);
//规范相交
if(c*d < 0)
return (area2*C.x - area1*D.x) / (area2 - area1);//叉积求交点,黑书上有
//非规范相交
if(c*d == 0)
{
if(c == 0)
return C.x;
else
return D.x;
}
return -inf;
}
void solve(int i, int j)
{
int k;
for(k = 1; k <= n; ++k)
{
if(!check(upperPoint[i],lowerPoint[j],upperPoint[k],lowerPoint[k]))
break;
}
//通过所有管道
if(k > n)
{
flag = true;
return;
}
//撞到管道壁上了 k要大于i,j才可以,如果小于i,j,光线就进不来这个管道了
else if(k > max(i,j))
{
double temp = intersection(upperPoint[i],lowerPoint[j],upperPoint[k],upperPoint[k-1]);
if(res < temp) res = temp;
temp = intersection(upperPoint[i],lowerPoint[j],lowerPoint[k],lowerPoint[k-1]);
if(res < temp) res = temp;
}
}
int main()
{
while(scanf("%d",&n) && n)
{
res = -inf;
flag = false;
for(int i = 1; i <= n; ++i)
{
scanf("%lf %lf",&upperPoint[i].x,&upperPoint[i].y);
lowerPoint[i].x = upperPoint[i].x;
lowerPoint[i].y = upperPoint[i].y - 1.0;
}
for(int i = 1; i <= n; ++i)
{
for(int j = 1; j <= n; ++j)
{
if(i != j)
solve(i,j);
}
if(flag) break;
}
if(flag) printf("Through all the pipe.\n");
else printf("%.2f\n",res);
}
return 0;
}