思路:先建图,建图的根据是判断两点的连线是否和线段有交,如果没交则计算两点的距离,然后做最短路。
贴了个求交的模板,所以代码有点多,我懒了。
代码
#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <cstring>
using namespace std;
const int PN = 100;
const int SN = 100;
const double INF = 9999999.0;
const double EPS = 1e-15; // 计算精度
bool vis[PN];
double dist[PN];
double G[PN][PN];
int n;
int pcnt;
int scnt;
struct cmp{
bool operator()(const int & a,const int & b){
return dist[a]<dist[b]||dist[a]==dist[b]&&a<b;
}
};
set <int,cmp> S;
struct point{
double x,y;
int segIndex;
point()
{}
point (double x0, double y0,int index): x(x0), y(y0),segIndex(index) {}
point (double x0, double y0): x(x0), y(y0) {}
};
struct seg{
point a;
point b;
seg()
{}
seg(point a0,point b0):a(a0),b(b0){}
};
point p[PN];
seg segs[SN];
inline double max(double x,double y)
{
return x > y ? x : y;
}
inline double min(double x, double y)
{
return x > y ? y : x;
}
inline bool ZERO(double x) // x == 0
{
return (fabs(x) < EPS);
}
inline bool ZERO(point p) // p == 0
{
return (ZERO(p.x) && ZERO(p.y));
}
inline bool EQ(double x, double y) // eqaul, x == y
{
return (fabs(x - y) < EPS);
}
inline bool NEQ(double x, double y) // not equal, x != y
{
return (fabs(x - y) >= EPS);
}
inline bool LT(double x, double y) // less than, x < y
{
return ( NEQ(x, y) && (x < y) );
}
inline bool GT(double x, double y) // greater than, x > y
{
return ( NEQ(x, y) && (x > y) );
}
inline bool LEQ(double x, double y) // less equal, x <= y
{
return ( EQ(x, y) || (x < y) );
}
inline bool GEQ(double x, double y) // greater equal, x >= y
{
return ( EQ(x, y) || (x > y) );
}
// 注意!!!
// 如果是一个很小的负的浮点数
// 保留有效位数输出的时候会出现-0.000这样的形式,
// 前面多了一个负号
// 这就会导致错误!!!!!!
// 因此在输出浮点数之前,一定要调用次函数进行修正!
inline double FIX(double x)
{
return (fabs(x) < EPS) ? 0 : x;
}
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
//二维矢量运算
bool operator==(point p1, point p2)
{
return ( EQ(p1.x, p2.x) && EQ(p1.y, p2.y) );
}
bool operator!=(point p1, point p2)
{
return ( NEQ(p1.x, p2.x) || NEQ(p1.y, p2.y) );
}
bool operator<(point p1, point p2)
{
if (NEQ(p1.x, p2.x)) {
return (p1.x < p2.x);
} else {
return (p1.y < p2.y);
}
}
point operator+(point p1, point p2)
{
return point(p1.x + p2.x, p1.y + p2.y);
}
point operator-(point p1, point p2)
{
return point(p1.x - p2.x, p1.y - p2.y);
}
double operator*(point p1, point p2) // 计算叉乘 p1 × p2
{
return (p1.x * p2.y - p2.x * p1.y);
}
double operator&(point p1, point p2) { // 计算点积 p1·p2
return (p1.x * p2.x + p1.y * p2.y);
}
void init()
{
for(int i=0;i<PN;i++)
{
dist[i] = INF;
for(int j=0;j<PN;j++)
{
G[i][j] = INF;
}
}
}
void dijkstra(int s ,double* min,double mat[][PN]){
int v[PN],i,j,k;
for (i=0;i<=pcnt;i++)
min[i]=INF,v[i]=0;
for (min[s]=0,j=0;j<=pcnt;j++){
for (k=-1,i=0;i<=pcnt;i++)
if (!v[i]&&(k==-1||min[i]<min[k]))
k=i;
for (v[k]=1,i=0;i<=pcnt;i++)
if (!v[i]&&!(fabs(mat[k][i]-INF)<=0.0001)&&min[k]+mat[k][i]<min[i])
min[i]=min[k]+mat[k][i];
}
}
bool LineSegIntersect(seg L1, seg L2) // 判断二维的两条线段是否相交
{
return ( GEQ( max(L1.a.x, L1.b.x), min(L2.a.x, L2.b.x) ) &&
GEQ( max(L2.a.x, L2.b.x), min(L1.a.x, L1.b.x) ) &&
GEQ( max(L1.a.y, L1.b.y), min(L2.a.y, L2.b.y) ) &&
GEQ( max(L2.a.y, L2.b.y), min(L1.a.y, L1.b.y) ) &&
LEQ( ((L2.a - L1.a) * (L1.b - L1.a)) * ((L2.b - L1.a) * (L1.b - L1.a)), 0 ) &&
LEQ( ((L1.a - L2.a) * (L2.b - L2.a)) * ((L1.b - L2.a) * (L2.b - L2.a)), 0 ) );
}
bool isInsert(int p1,int p2)
{
//bool flag = true;
int l = p[p1].segIndex;
int r = p[p2].segIndex;
double tx1 = p[p1].x;
double tx2 = p[p2].x;
if(p1!=0)
{
while(segs[l].a.x==tx1)l++;
}
if(p2!=pcnt)
{
while(segs[r].a.x==tx2)r--;
}
for(int i=l;i<=r;i++)
{
if(LineSegIntersect(seg(p[p1],p[p2]),segs[i]))
{
return true;
}
}
return false;
}
inline double caldis(int p1,int p2)
{
return sqrt((p[p1].x - p[p2].x) * (p[p1].x - p[p2].x) + (p[p1].y - p[p2].y)*(p[p1].y - p[p2].y));
}
void makeGraph()
{
for(int i=0;i<pcnt;i++)
for(int j=i+1;j<=pcnt;j++)
{
if(!isInsert(i,j))
{
G[i][j] = G[j][i] = caldis(i,j);
}
}
}
void input()
{
double x,y1,y2,y3,y4;
while(scanf("%d",&n)!=EOF&&n!=-1)
{
init();
pcnt = 0;
scnt = -1;
p[0] = point(0,5,scnt+1);
for(int i=0;i<n;i++)
{
scanf("%lf",&x);
scanf("%lf%lf%lf%lf",&y1,&y2,&y3,&y4);
p[++pcnt] = point(x,y1,scnt+1);
p[++pcnt] = point(x,y2,scnt+2);
p[++pcnt] = point(x,y3,scnt+2);
p[++pcnt]= point(x,y4,scnt+3);
segs[++scnt] = seg(point(x,0),p[pcnt-3]);
segs[++scnt] = seg(p[pcnt-2],p[pcnt-1]);
segs[++scnt] = seg(p[pcnt],point(x,10));
}
p[++pcnt] = point(10,5,scnt);
makeGraph();
dijkstra(0,dist,G);
printf("%.2f\n",dist[pcnt]);
}
}
int main()
{
input();
return 0;
}
#include <cmath>
#include <cstdio>
#include <set>
#include <cstring>
using namespace std;
const int PN = 100;
const int SN = 100;
const double INF = 9999999.0;
const double EPS = 1e-15; // 计算精度
bool vis[PN];
double dist[PN];
double G[PN][PN];
int n;
int pcnt;
int scnt;
struct cmp{
bool operator()(const int & a,const int & b){
return dist[a]<dist[b]||dist[a]==dist[b]&&a<b;
}
};
set <int,cmp> S;
struct point{
double x,y;
int segIndex;
point()
{}
point (double x0, double y0,int index): x(x0), y(y0),segIndex(index) {}
point (double x0, double y0): x(x0), y(y0) {}
};
struct seg{
point a;
point b;
seg()
{}
seg(point a0,point b0):a(a0),b(b0){}
};
point p[PN];
seg segs[SN];
inline double max(double x,double y)
{
return x > y ? x : y;
}
inline double min(double x, double y)
{
return x > y ? y : x;
}
inline bool ZERO(double x) // x == 0
{
return (fabs(x) < EPS);
}
inline bool ZERO(point p) // p == 0
{
return (ZERO(p.x) && ZERO(p.y));
}
inline bool EQ(double x, double y) // eqaul, x == y
{
return (fabs(x - y) < EPS);
}
inline bool NEQ(double x, double y) // not equal, x != y
{
return (fabs(x - y) >= EPS);
}
inline bool LT(double x, double y) // less than, x < y
{
return ( NEQ(x, y) && (x < y) );
}
inline bool GT(double x, double y) // greater than, x > y
{
return ( NEQ(x, y) && (x > y) );
}
inline bool LEQ(double x, double y) // less equal, x <= y
{
return ( EQ(x, y) || (x < y) );
}
inline bool GEQ(double x, double y) // greater equal, x >= y
{
return ( EQ(x, y) || (x > y) );
}
// 注意!!!
// 如果是一个很小的负的浮点数
// 保留有效位数输出的时候会出现-0.000这样的形式,
// 前面多了一个负号
// 这就会导致错误!!!!!!
// 因此在输出浮点数之前,一定要调用次函数进行修正!
inline double FIX(double x)
{
return (fabs(x) < EPS) ? 0 : x;
}
//////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
//二维矢量运算
bool operator==(point p1, point p2)
{
return ( EQ(p1.x, p2.x) && EQ(p1.y, p2.y) );
}
bool operator!=(point p1, point p2)
{
return ( NEQ(p1.x, p2.x) || NEQ(p1.y, p2.y) );
}
bool operator<(point p1, point p2)
{
if (NEQ(p1.x, p2.x)) {
return (p1.x < p2.x);
} else {
return (p1.y < p2.y);
}
}
point operator+(point p1, point p2)
{
return point(p1.x + p2.x, p1.y + p2.y);
}
point operator-(point p1, point p2)
{
return point(p1.x - p2.x, p1.y - p2.y);
}
double operator*(point p1, point p2) // 计算叉乘 p1 × p2
{
return (p1.x * p2.y - p2.x * p1.y);
}
double operator&(point p1, point p2) { // 计算点积 p1·p2
return (p1.x * p2.x + p1.y * p2.y);
}
void init()
{
for(int i=0;i<PN;i++)
{
dist[i] = INF;
for(int j=0;j<PN;j++)
{
G[i][j] = INF;
}
}
}
void dijkstra(int s ,double* min,double mat[][PN]){
int v[PN],i,j,k;
for (i=0;i<=pcnt;i++)
min[i]=INF,v[i]=0;
for (min[s]=0,j=0;j<=pcnt;j++){
for (k=-1,i=0;i<=pcnt;i++)
if (!v[i]&&(k==-1||min[i]<min[k]))
k=i;
for (v[k]=1,i=0;i<=pcnt;i++)
if (!v[i]&&!(fabs(mat[k][i]-INF)<=0.0001)&&min[k]+mat[k][i]<min[i])
min[i]=min[k]+mat[k][i];
}
}
bool LineSegIntersect(seg L1, seg L2) // 判断二维的两条线段是否相交
{
return ( GEQ( max(L1.a.x, L1.b.x), min(L2.a.x, L2.b.x) ) &&
GEQ( max(L2.a.x, L2.b.x), min(L1.a.x, L1.b.x) ) &&
GEQ( max(L1.a.y, L1.b.y), min(L2.a.y, L2.b.y) ) &&
GEQ( max(L2.a.y, L2.b.y), min(L1.a.y, L1.b.y) ) &&
LEQ( ((L2.a - L1.a) * (L1.b - L1.a)) * ((L2.b - L1.a) * (L1.b - L1.a)), 0 ) &&
LEQ( ((L1.a - L2.a) * (L2.b - L2.a)) * ((L1.b - L2.a) * (L2.b - L2.a)), 0 ) );
}
bool isInsert(int p1,int p2)
{
//bool flag = true;
int l = p[p1].segIndex;
int r = p[p2].segIndex;
double tx1 = p[p1].x;
double tx2 = p[p2].x;
if(p1!=0)
{
while(segs[l].a.x==tx1)l++;
}
if(p2!=pcnt)
{
while(segs[r].a.x==tx2)r--;
}
for(int i=l;i<=r;i++)
{
if(LineSegIntersect(seg(p[p1],p[p2]),segs[i]))
{
return true;
}
}
return false;
}
inline double caldis(int p1,int p2)
{
return sqrt((p[p1].x - p[p2].x) * (p[p1].x - p[p2].x) + (p[p1].y - p[p2].y)*(p[p1].y - p[p2].y));
}
void makeGraph()
{
for(int i=0;i<pcnt;i++)
for(int j=i+1;j<=pcnt;j++)
{
if(!isInsert(i,j))
{
G[i][j] = G[j][i] = caldis(i,j);
}
}
}
void input()
{
double x,y1,y2,y3,y4;
while(scanf("%d",&n)!=EOF&&n!=-1)
{
init();
pcnt = 0;
scnt = -1;
p[0] = point(0,5,scnt+1);
for(int i=0;i<n;i++)
{
scanf("%lf",&x);
scanf("%lf%lf%lf%lf",&y1,&y2,&y3,&y4);
p[++pcnt] = point(x,y1,scnt+1);
p[++pcnt] = point(x,y2,scnt+2);
p[++pcnt] = point(x,y3,scnt+2);
p[++pcnt]= point(x,y4,scnt+3);
segs[++scnt] = seg(point(x,0),p[pcnt-3]);
segs[++scnt] = seg(p[pcnt-2],p[pcnt-1]);
segs[++scnt] = seg(p[pcnt],point(x,10));
}
p[++pcnt] = point(10,5,scnt);
makeGraph();
dijkstra(0,dist,G);
printf("%.2f\n",dist[pcnt]);
}
}
int main()
{
input();
return 0;
}