首页 > 代码库 > POJ 1066 Treasure Hunt(线段相交&&转换)

POJ 1066 Treasure Hunt(线段相交&&转换)

Treasure Hunt


大意:在一个矩形区域内,有n条线段,线段的端点是在矩形边上的,有一个特殊点,问从这个点到矩形边的最少经过的线段条数最少的书目,穿越只能在中点穿越。

思路:需要巧妙的转换一下这个问题,因为从一个点到终点不可能“绕过”围墙,只能穿过去,所以门是否开在中点是无所谓的,只要求四周线段中点到终点的线段与墙的最少交点个数即可。更进一步,实际上,只需判断四周围墙的所有点与终点的连线与内墙的最少交点加一即可。

struct Point{
    double x, y;
} A, B, P[65], aim;
struct Line{
    Point a, b;
} L[35];

int n;

double xmult(Point p1, Point p2, Point p)
{
    return (p1.x-p.x)*(p2.y-p.y)-(p2.x-p.x)*(p1.y-p.y);
}

bool Intersection(Line u, Line v)
{
    return (max(u.a.x, u.b.x) >= min(v.a.x, v.b.x))
        && (max(v.a.x, v.b.x) >= min(u.a.x, u.b.x))
        && (max(u.a.y, u.b.y) >= min(v.a.y, v.b.y))
        && (max(v.a.y, v.b.y) >= min(u.a.y, u.b.y))
        && (xmult(u.a, v.a, u.b)*xmult(u.a, u.b, v.b) > eps)
        && (xmult(v.a, u.a, v.b)*xmult(v.a, v.b, u.b) > eps);
}

void Solve()
{
   scanf("%d", &n);
   int t = 0;
   for(int i = 0; i < n; ++i)
   {
       scanf("%lf%lf%lf%lf", &A.x, &A.y, &B.x, &B.y);
       P[t++] = L[i].a = A;
       P[t++] = L[i].b = B;
   }
   scanf("%lf%lf", &aim.x, &aim.y);
   int ans = INF;
   for(int i = 0; i < t; ++i)
   {
       int cnt = 0;
       Line p = (Line){aim, P[i]};
       for(int j = 0; j < n; ++j)
       {
           if(Intersection(p, L[j]))
           {
               cnt++;
           }
       }
       if(cnt < ans)
       {
           ans = cnt;
       }
   }
   printf("Number of doors = %d\n", n?ans+1:1);
}