最近刚刚开始接触计算几何。一口气还是刷了些题,都没来得及写blog。这十多题大部分都是巨水的题目,也算是入门了。
这道题是第一道,没有使用任何模板,写法也显得十分菜鸟,后面几题的思路和代码风格就渐渐成形了。先说题目
题目大意:
有一个包含障碍墙的房间,你要去寻到一条穿过房间的最短路径。这个房间始终位于x = 0, x = 10, y = 0和 y = 10. 路径的起点和终点始终是(0,5)和(10,5)。
房间里也有0~18面垂直的障碍墙,每面墙上有两扇门。下面的数字描述了一个房间和最短路径。
输入:
一个房间的说明如下:
2
4 2 7 8 9
7 3 4 5 6 7
第一行包含一个数表示室内墙的数量。接下来每一行描述了一面墙,包含五个实数,第一个数是墙的x坐标(0 < x < 10),其余的四个数是门的端点处的y坐标。墙的x坐标是递增的,每一行的y坐标也是递增的。输入文件包含一组或多组数据。当墙的数量为-1时数据结束。
输出:
对于每一个房间应该输出一行。包含最短路径长度,保留两位小数。
输入样例:
1
5 4 6 7 8
2
4 2 7 8 9
7 3 4.5 6 7
-1
解题思路:
这道题只要能建立一个最短路模型,就能算出答案。建立最短路时需要判断线段相交的问题。当时对线段相交的问题脑袋里面一团浆糊,也不知道什么是规范相交和非规范相交。如果有人做这道题的时候有同样的问题,那就去看看黑书吧,上面对线段相交花了好几页来讲,看完之后豁然开朗。
#include <cstdio>
#include <cstring>
#include <cmath>
struct point {
double x, y;
};
struct line{
point a, b;
};
int n;
line l[300];
point p[600];
int nump, numl;
double y[40];
double dis[1000][1000];
int cmp( double a){
if(fabs(a) < 10e-8) return 0;
if(a > 0) return 1;
else return -1;
}
double min(double a, double b){
if( cmp(a - b) <= 0) return a;
return b;
}
double max(double a, double b){
if( cmp(a - b) >= 0) return a;
return b;
}
point operator + (const point &a, const point &b){
point p;
p.x = a.x + b.x;
p.y = a.y + b.y;
return p;
}
point operator - (const point &a, const point &b){
point p;
p.x = a.x - b.x;
p.y = a.y - b.y;
return p;
}
bool operator == (const point &a, const point &b){
return cmp(a.x - b.x) == 0 && cmp(a.y - b.y) == 0;
}
point makePoint(double a, double b){
point p;
p.x = a;
p.y = b;
return p;
}
line makeLine(point a, point b){
line l;
l.a = a;
l.b = b;
return l;
}
line makeLine(double x1, double y1, double x2, double y2){
point a, b;
line l;
a.x = x1;
a.y = y1;
b.x = x2;
b.y = y2;
l.a = a;
l.b = b;
return l;
}
double dist(point a, point b){
return sqrt( (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
double det( point a, point b){
return (a.x * b.y - a.y * b.x);
}
int OK(int i, int j){
point a = p[i], b = p[j];
if(p[i] == p[j]) return 1;
for(int i = 0; i < numl; i++){
point c = l[i].a, d = l[i].b;
if(min(a.x, b.x) <= max(c.x, d.x) && min(c.x, d.x) <= max(a.x, b.x)
&& min(a.y, b.y) <= max(c.y, d.y) && min(c.y, d.y) <= max(a.y, b.y)
&& det(c - a, b - a) * det(b - a, d - a) > 0
&& det(a - c, d - c) * det(d - c, b - c) > 0) return 0;
}
return 1;
}
void init(){
memset(p, 0, sizeof(p));
memset(l, 0, sizeof(l));
for(int i = 0; i < 90; i++){
for(int j = 0; j < 90; j++) dis[i][j]=123456789.0;
}
numl = 0;
nump = 0;
}
double x;
int main(){
while (scanf("%d", &n) && n != -1){
init();
p[nump++] = makePoint(0.0, 5.0);
p[nump++] = makePoint(10.0, 5.0);
for(int i = 0; i < n; i++){
scanf("%lf%lf%lf%lf%lf", &x ,&y[0], &y[1], &y[2], &y[3]);
for(int j = 0; j < 4; j++) p[nump++] = makePoint(x, y[j]);
l[numl++] = makeLine( x, 0.0, x, y[0]);
l[numl++] = makeLine( x, y[1], x, y[2]);
l[numl++] = makeLine( x, y[3], x, 10.0);
}
for(int i = 0;i < nump; i++){
for(int j = i + 1; j < nump; j++) if (OK(i, j)){
// printf("%lf %lf %lf %lf\n",p[i].x , p[i].y, p[j].x, p[j].y);
dis[i][j] = dis[j][i] = dist(p[i], p[j]);
}
}
for(int k = 0; k < nump ;k++){
for(int i = 0; i < nump; i++){
for(int j = 0; j < nump; j++)if( i != j && i != k && j != k){
dis[i][j]=min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
printf("%.2f\n", dis[0][1]);
}
return 0;
}