题意:给定n堵墙,现在要你从(0,5)走去(10,5)的最短距离
思路:刚开始还想模拟,就是从(0,5)走,每次x向右一格,然后判断有没和线段相交就可以。但是它的们有可能是小数形式给出的,这样就GG了(x--x+1中可能存在很多门)。正确的方法应该是建图,对于所有门,他们都有端点的,先把他们加入到图中,包括起点的话,一共有num个点吧。然后暴力判断e[i][j]是否能到达就可以,这里用线段相交就可以判断。然后floyd一下就好。bug点:门的端点不应该加进来,就是(x,0)、(x,10)这样的点不应该加入图中,因为那个是死角,不能出去了。
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const double eps = 1e-8; const int maxn = 100+20; bool same (double a,double b) { return fabs(a-b)<eps; } struct coor { double x,y; coor(){} coor(double xx,double yy):x(xx),y(yy){} double operator ^(coor rhs) const //计算叉积(向量积) { return x*rhs.y - y*rhs.x; } coor operator -(coor rhs) const //坐标相减,a-b得到向量ba { return coor(x-rhs.x,y-rhs.y); } double operator *(coor rhs) const //数量积 { return x*rhs.x + y*rhs.y; } bool operator ==(coor rhs) const { return same(x,rhs.x)&&(y,rhs.y);//same的定义其实就是和eps比较 } }a[maxn]; struct Line { coor point1,point2; Line(){} Line(coor xx,coor yy):point1(xx),point2(yy){} bool operator &(Line rhs) const //判断直线和rhs线段是否相交 { //自己表示一条直线,然而rhs表示的是线段 //思路,判断rhs线段上两个端点是否在this直线的同一侧即可,用一侧,就不相交 coor ff1 = point2 - point1; //直线的方向向量 return ( ((rhs.point1-point1)^ff1) * ((rhs.point2-point1)^ff1) ) <= 0;//符号不同或者有0,证明相交 } }LINE[maxn]; bool OnSegment (coor a,coor b,coor c) //判断点C是否在线段ab上 { double min_x = min(a.x,b.x), min_y = min(a.y,b.y); double max_x = max(a.x,b.x), max_y = max(a.y,b.y); if (c.x>=min_x && c.x<=max_x && c.y>=min_y && c.y<=max_y) return true; else return false; } bool SegmentIntersect (coor a,coor b,coor c,coor d) { double d1 = (b-a)^(d-a); //direction(a,b,d);以a为起点,计算ab和ab的叉积 double d2 = (b-a)^(c-a); double d3 = (d-c)^(a-c); double d4 = (d-c)^(b-c); if (d1*d2<0 && d3*d4<0) return true; else if (d1 == 0 && OnSegment(a,b,d)) return true; else if (d2 == 0 && OnSegment(a,b,c)) return true; else if (d3 == 0 && OnSegment(c,d,a)) return true; else if (d4 == 0 && OnSegment(c,d,b)) return true; else return false; } int n; int all=0; double dis (coor a,coor b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double e[maxn][maxn]; void work () { all = 0; int num=0; for (int i=1;i<=n;++i) { double aa,bb,cc,dd,ee; scanf("%lf%lf%lf%lf%lf",&aa,&bb,&cc,&dd,&ee); ++all; LINE[all].point1 = coor(aa,0); //a[++num]=coor(aa,0); LINE[all].point2 = coor(aa,bb);a[++num]=coor(aa,bb); ++all; LINE[all].point1 = coor(aa,cc);a[++num]=coor(aa,cc); LINE[all].point2 = coor(aa,dd);a[++num]=coor(aa,dd); ++all; LINE[all].point1 = coor(aa,ee);a[++num]=coor(aa,ee); LINE[all].point2 = coor(aa,10);//a[++num]=coor(aa,10); } a[++num]=coor(0,5); a[++num]=coor(10,5); //memset(e,0x3f,sizeof e); for (int i=1;i<=maxn-20;++i) { for (int j=1;j<=maxn-20;++j) { e[i][j]=100000000.0; } } for (int i=1;i<=num;++i) { for (int j=i+1;j<=num;++j) { int k; //if (same(a[j].y,0)||same(a[j].y,10)||same(a[i].y,0)||same(a[i].y,10)) continue; for (k=1;k<=all;++k) { if (LINE[k].point1==a[i]||LINE[k].point1==a[j]||LINE[k].point2==a[i]||LINE[k].point2==a[j]) continue; if (SegmentIntersect(a[i],a[j],LINE[k].point1,LINE[k].point2)) break; } if (k==all+1) e[i][j]=e[j][i]=dis(a[i],a[j]); } } for (int i=1;i<=num;++i) { for (int j=1;j<=num;j++) { for (int k=1;k<=num;++k) { if (e[j][k]>e[j][i]+e[i][k]) e[j][k]=e[j][i]+e[i][k]; } } } printf ("%0.2f ",e[num-1][num]); //printf ("%0.2f ",e[num-1][1]); return; } int main() { #ifdef local freopen("data.txt","r",stdin); #endif while(scanf("%d",&n)!=EOF && n!=-1) work(); return 0; }