POJ 1066 Treasure Hunt

POJ_1066

    一个比较直观的思路就是,把每个房间看作一个点,每个门看作一条边,然后去BFS求解。但是,对于房间的确定是很棘手的,很难用有效的手段将这些房间一一标号。

    于是,不妨转化一下思路,把每个门看作一个点。门还是比较好找的,对于任意一条直线,现将其上所有交点找到,相邻的两个交点的中点自然就是门。这样还剩下一个问题就是这些门之间的边该如何构造?我们任意连一下两个门,不难发现,如果这两个门可以直接到达的话,那么这两个门之间连线形成的线段是和其他线段都不会形成规范相交的,而如果这两个门不可以直接到达的话,则至少会和某一条线段形成规范相交的。

    因此,我们就有了思路一:

    首先枚举线段,将这条线段上的每个交点找到,进而相邻两个交点之间的中点就是一个门。这样首先将所有的门都找到。之后,再通过判断两个门之间连线形成的线段是否会和其他线段形成规范相交,从而构造出门之间的边。最后,从起点开始做BFS,当遇到某个在四条边上点即结束BFS。

    同时,这个题目还有另一个更为简单的思路二:

    如果我们将起点和四条边上的某个门,也就是最终的某个出口连一条线段,就会发现这条线段会和某些线段相交,而如果非要从这个出口出去的话,那么这些线段(指的都是端点在四条边上的长线段)都是必然要穿过的(结合图就会比较容易想明白)。所以,这些线段的数量再加1就是从这个出口出去最少经过的门数。因此,我们可以枚举四条边上的门作为出口,然后一一判断起点与这些出口所连成的线段和多少其他的线段相交,找到这个数量的最小值再加1就是最终的结果。

    下面的程序是思路一的程序。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAXD 50
#define MAXP 1010
#define MAXM 1000010
#define zero 1e-8
int N, first[MAXP], next[MAXM], e, v[MAXM], r[MAXD], p, cur, d[MAXP], q[MAXP];
double sx, sy, x1[MAXD], x2[MAXD], y1[MAXD], y2[MAXD], tx[MAXD], ty[MAXD], x[MAXP], y[MAXP];
int cmp(const void *_p, const void *_q)
{
int *p = (int *)_p;
int *q = (int *)_q;
double t1 = (tx[*p] - x1[cur]) * (tx[*p] - x1[cur]) + (ty[*p] - y1[cur]) * (ty[*p] - y1[cur]);
double t2 = (tx[*q] - x1[cur]) * (tx[*q] - x1[cur]) + (ty[*q] - y1[cur]) * (ty[*q] - y1[cur]);
return t1 < t2 ? -1 : 1;
}
double fabs(double x)
{
return x < 0 ? -x : x;
}
int dcmp(double x)
{
if(fabs(x) < zero)
return 0;
if(x < 0)
return -1;
return 1;
}
void init()
{
int i, j, k;
for(i = 0; i < N; i ++)
scanf("%lf%lf%lf%lf", &x1[i], &y1[i], &x2[i], &y2[i]);
scanf("%lf%lf", &sx, &sy);
x1[N] = 0, y1[N] = 0, x2[N] = 0, y2[N] = 100;
++ N;
x1[N] = 0, y1[N] = 0, x2[N] = 100, y2[N] = 0;
++ N;
x1[N] = 100, y1[N] = 0, x2[N] = 100, y2[N] = 100;
++ N;
x1[N] = 0, y1[N] = 100, x2[N] = 100, y2[N] = 100;
++ N;
p = 0;
x[p] = sx, y[p] = sy;
++ p;
}
double det(double x1, double y1, double x2, double y2)
{
return x1 * y2 - x2 * y1;
}
double cross(int i, double x, double y)
{
return det(x2[i] - x1[i], y2[i] - y1[i], x - x1[i], y - y1[i]);
}
int check(int i, int j)
{
int k;
double t1, t2, t3, t4;
for(k = 0; k < N; k ++)
{
t1 = det(x2[k] - x1[k], y2[k] - y1[k], x[i] - x1[k], y[i] - y1[k]);
t2 = det(x2[k] - x1[k], y2[k] - y1[k], x[j] - x1[k], y[j] - y1[k]);
t3 = det(x[j] - x[i], y[j] - y[i], x1[k] - x[i], y1[k] - y[i]);
t4 = det(x[j] - x[i], y[j] - y[i], x2[k] - x[i], y2[k] - y[i]);
if(dcmp(t1) * dcmp(t2) < 0 && dcmp(t3) * dcmp(t4) < 0)
return 0;
}
return 1;
}
void add(int x, int y)
{
v[e] = y;
next[e] = first[x];
first[x] = e;
++ e;
}
void build()
{
int i, j, k;
e = 0;
memset(first, -1, sizeof(first));
for(i = 0; i < p; i ++)
for(j = i + 1; j < p; j ++)
if(check(i, j))
{
add(i, j);
add(j, i);
}
}
void prepare()
{
int i, j, k, nk, t;
double t1, t2, t3, t4;
for(i = 0; i < N; i ++)
{
t = 0;
for(j = 0; j < N; j ++)
if(j != i)
{
t1 = cross(i, x1[j], y1[j]);
t2 = cross(i, x2[j], y2[j]);
t3 = cross(j, x1[i], y1[i]);
t4 = cross(j, x2[i], y2[i]);
if(dcmp(t1) * dcmp(t2) <= 0 && dcmp(t3) * dcmp(t4) <= 0)
{
tx[t] = (fabs(t2) * x1[j] + fabs(t1) * x2[j]) / (fabs(t1) + fabs(t2));
ty[t] = (fabs(t2) * y1[j] + fabs(t1) * y2[j]) / (fabs(t1) + fabs(t2));
++ t;
}
}
for(j = 0; j < t; j ++)
r[j] = j;
cur = i;
qsort(r, t, sizeof(r[0]), cmp);
for(j = 0; j < t - 1; j ++)
{
k = r[j], nk = r[j + 1];
if(fabs(tx[k] - tx[nk]) < zero && fabs(ty[k] - ty[nk]) < zero)
continue;
x[p] = (tx[k] + tx[nk]) / 2, y[p] = (ty[k] + ty[nk]) / 2;
++ p;
}
}
build();
}
void solve()
{
int i, j, k, u, front, rear;
prepare();
front = rear = 0;
memset(d, 0x3f, sizeof(d));
d[0] = 0;
q[rear ++] = 0;
while(front < rear)
{
u = q[front ++];
if(fabs(x[u]) < zero || fabs(x[u] - 100) < zero || fabs(y[u]) < zero || fabs(y[u] - 100) < zero)
break;
for(i = first[u]; i != -1; i = next[i])
if(d[u] + 1 < d[v[i]])
{
d[v[i]] = d[u] + 1;
q[rear ++] = v[i];
}
}
printf("Number of doors = %d\n", d[u]);
}
int main()
{
while(scanf("%d", &N) == 1)
{
init();
solve();
}
return 0;
}


你可能感兴趣的:(poj)