题目意思是对于一个给定的房间和固定的起点和终点,其里面有好几堵墙,求起点到终点的最短路径。
黑书练习题。具体解法是把题中所给的所有点看成是图中的一一对应的点,点与点之间可以连线当且仅当该线段与墙不相交。最后用dijk求起点到终点的最短路即可。
代码很长,一般的计算几何题都是如此,细心是关键:
- #include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int M=200;
const int N=10000;
const double eps=1e-8;
const double inf=999999999.9;
struct point
{
double x,y;
}points[M];
struct line
{
point a,b;
}lines[M];
struct node
{
int v;
double w;
int next;
}edge[N];
int head[M],num;
double dis[M];
int cnt,cnt1,n; - void init()
{
int i;
for(i=0;i<=4*n+5;i++)
head[i]=-1;
num=0;
} - void addege(int u,int v)
{
edge[num].v=v;
edge[num].w=sqrt((points[u].x-points[v].x)*(points[u].x-points[v].x)+(points[u].y-points[v].y)*(points[u].y-points[v].y));
edge[num].next=head[u];
head[u]=num++;
} - double crossmul(double x1,double y1,double x2,double y2)
{
return x1*y2-x2*y1;
} - double dotdel(double x1,double y1,double x2,double y2)
{
return x1*x2+y1*y2;
} - int cmpzero(double d)
{
return (fabs(d)<eps)?0:(d>0?1:-1);
} - int cross(point a,point c,point d)
{
return cmpzero(crossmul(a.x-c.x,a.y-c.y,d.x-c.x,d.y-c.y));
} - int between(point a,point c,point d)
{
return cmpzero(dotdel(c.x-a.x,c.y-a.y,d.x-a.x,d.y-a.y))!=1;
} - //1为规范相交,2为不规范相交,0为不相交
- int seg_intersect(point a,point b,point c,point d)
{
int a_cd=cross(a,c,d);
if(a_cd==0 && between(a,c,d))
return 2;
int b_cd=cross(b,c,d);
if(b_cd==0 && between(b,c,d))
return 2;
int c_ab=cross(c,a,b);
if(c_ab==0 && between(c,a,b))
return 2;
int d_ab=cross(d,a,b);
if(d_ab==0 && between(d,a,b))
return 2;
if((a_cd^b_cd)==-2 && (c_ab^d_ab)==-2)
return 1;
return 0;
} - struct cmp
{
bool operator() (const int &a,const int &b)
{
return dis[b]>dis[a];
}
}; - void dijk() //dijk算法求最短路
{
priority_queue<int,vector<int>,cmp > Q;
int i,j;
for(i=0;i<M;i++)
{
dis[i]=inf;
}
dis[0]=0;
Q.push(0);
while(!Q.empty())
{
int i=Q.top();
Q.pop();
for(j=head[i];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(dis[v]>dis[i]+edge[j].w)
{
dis[v]=dis[i]+edge[j].w;
Q.push(v);
}
}
}
} - void build()//构图
{
int i,j,k;
for(i=0;i<cnt;i++)
{
for(j=i+1;j<cnt;j++)
{
if(j<=i+4)
{
if(points[j].x>points[i].x)
{
addege(i,j);
}
}
else
{
bool flag=true;
for(k=0;k<cnt1;k++)
{
if(lines[k].a.x>points[i].x)
{
if(seg_intersect(points[i],points[j],lines[k].a,lines[k].b)==1)
{
flag=false;break;
}
}
}
if(flag)
{
addege(i,j);
}
}
}
}
} - int main()
{
// freopen("in.txt","r",stdin);
while(scanf("%d",&n)==1)
{
if(n==-1) break;
init();
cnt1=0;
cnt=1;
points[0].x=0;
points[0].y=5;
point p;
int i,j,k,s;
double x,y;
for(i=1;i<=n;i++)
{
scanf("%lf",&x);
for(j=0;j<4;j++)
{
scanf("%lf",&y);
points[cnt].x=x;
points[cnt].y=y;
if(j==0)
{
p.x=x;
p.y=0;
lines[cnt1].a=p;
lines[cnt1].b=points[cnt];
cnt++;
cnt1++;
}
else if(j==3)
{
p.x=x;
p.y=10;
lines[cnt1].a=points[cnt];
lines[cnt1].b=p;
cnt++;
cnt1++;
}
else if(j==2)
{
lines[cnt1].a=points[cnt-1];
lines[cnt1].b=points[cnt];
cnt++;
cnt1++;
}
else cnt++;
}
}
points[cnt].x=10;
points[cnt].y=5;
cnt++;
build();
dijk();
printf("%.2lf/n",dis[cnt-1]);
}
return 0;
}