题解
- 暴力任意两个点之间连线,判断有没有线段与之相交,没有求两点之间的距离。否则inf
- 跑最短路,floyd方便不超时。
- 我对点的处理有点麻烦
- x号点和y号点之间的线段编号范围
1列:1,2,3,4包含边1 2 3
2列:5,6,7,8包含边4 5 6
3列:9,10,11,12包含边7 8 9
…………
- 4n-3--4n点包含边3n-2--3n
- x点对应的列好为(x+3)/4
- 起点和终点单独处理
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;
double const eps = 1e-8;
double const inf = 1e20;
int const N = 100;
int n,edge_cnt,point_cnt;
double mp[N][N];
typedef struct Point{ //点和向量
double x,y;
Point(){};
Point(double x,double y):x(x),y(y){};
Point operator - (const Point& e)const{ //减
return Point(x - e.x,y - e.y);
}
double operator ^ (const Point& e)const{ //叉乘
return x * e.y - y * e.x;
}
double operator * (const Point& e)const{
return x * e.x + y * e.y;
}
}Vector;
struct Line{ //直线的定义
Point a,b;
Line(){};
Line(Point a,Point b):a(a),b(b){}
};
Line line[N];
Point p[N];
int dcmp(double x){ //判断符号
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
}
double Distance(Point a,Point b){
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
bool onsegment(Point p,Point a1,Point a2){
return dcmp((a1 - p) ^ (a2 - p)) == 0 && dcmp((a1 - p) * (a2 - p)) < 0;
}
bool segment_intersection(Line line1,Line line2){ //判断线段是否相交,相交返回true
double c1 = (line1.b - line1.a) ^ (line2.a - line1.a);
double c2 = (line1.b - line1.a) ^ (line2.b - line1.a);
double c3 = (line2.b - line2.a) ^ (line1.a - line2.a);
double c4 = (line2.b - line2.a) ^ (line1.b - line2.a);
return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}
void build_edge(){ //连接任意两点,没有与任意一条边相交,就加入边
for(int i=1;i<=point_cnt;i++){
for(int j=1;j<=point_cnt;j++){
if(i == j) mp[i][j] = mp[j][i] = 0;
else mp[i][j] = mp[j][i] = inf;
}
}
bool flag;
int to,from;
for(int i=1;i<=point_cnt-2;i++){
for(int j=i+1;j<=point_cnt-2;j++){
from = (i + 3) / 4, to = (j + 3) /4;
if(from == to) continue; //在同一列上
flag = true;
for(int k=3*from-2;k<=3*to && flag;k++)
if(segment_intersection(Line(p[i],p[j]),line[k])) flag = false; //如果与任意一条线段相交
if(flag) mp[j][i] = mp[i][j] = Distance(p[i],p[j]);
}
}
for(int i=1;i<=point_cnt-2;i++){ //起点和终点与中间的点连边
flag = true;
to = (i + 3) / 4 - 1;
for(int j=1;j<=3*to && flag;j++)
if(segment_intersection(Line(p[i],p[point_cnt-1]),line[j])) flag = false;
if(flag) mp[point_cnt-1][i] = mp[i][point_cnt-1] = Distance(p[i],p[point_cnt-1]);
to = (i + 3) / 4 + 1;
flag = true;
for(int j=3*to-2;j<=edge_cnt && flag;j++)
if(segment_intersection(Line(p[i],p[point_cnt]),line[j])) flag = false;
if(flag) mp[point_cnt][i] = mp[i][point_cnt] = Distance(p[i],p[point_cnt]);
}
flag = true;
for(int i=1;i<=edge_cnt;i++)
if(segment_intersection(Line(p[point_cnt],p[point_cnt-1]),line[i])) flag = false;
if(flag) mp[point_cnt][point_cnt-1] = mp[point_cnt-1][point_cnt] = Distance(p[point_cnt-1],p[point_cnt]);
}
void Floyd(){
for(int i=1;i<=point_cnt;i++)
for(int j=1;j<=point_cnt;j++)
for(int k=1;k<=point_cnt;k++)
if(mp[i][k] < inf && mp[k][j] < inf && mp[i][k] + mp[k][j] < mp[i][j])
mp[i][j] = mp[i][k] + mp[k][j];
}
int main(){
while(~scanf("%d",&n) && n != -1){
edge_cnt = point_cnt = 0;
for(int i=0;i<n;i++){
double x,y1,y2,y3,y4;
scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
line[++edge_cnt] = Line(Point(x,0),p[++point_cnt] = Point(x,y1));
line[++edge_cnt] = Line(p[++point_cnt] = Point(x,y2),p[++point_cnt] = Point(x,y3));
line[++edge_cnt] = Line(p[++point_cnt] = Point(x,y4),Point(x,10));
}
p[++point_cnt] = Point(0,5);
p[++point_cnt] = Point(10,5);
build_edge();
Floyd();
printf("%.2f\n",mp[point_cnt-1][point_cnt]);
}
return 0;
}