版权声明:转载注明下出处就行了。 https://blog.csdn.net/LJD201724114126/article/details/83586689
题目链接:poj 1556
题意:房间里有n堵墙,每面墙上有两扇门,从(0, 5)走到(10, 5),中间有一些门,走的路是直线,问最短的距离。
题解:建图,再求个最短路就行了,这题主要难在建图。
参考博客:https://www.cnblogs.com/Running-Time/p/4906367.html
https://blog.csdn.net/hq572241670/article/details/41550849?locationNum=2&fps=1
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn=300;
struct point
{
double x,y;
point(){}
point(double _x,double _y){
x=_x;y=_y;
}
};
point operator + (point a,point b) {return point(a.x+b.x,a.y+b.y);}
point operator - (point a,point b) {return point(a.x-b.x,a.y-b.y);}
point operator * (point a,double p) { return point(a.x*p,a.y*p);}
point operator / (point a,double p){ return point(a.x/p,a.y/p);}
bool operator < (const point &a,const point &b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
const double esp=1e-8;
int dcmp(double x){
if(fabs(x)<esp) return 0;
else return x<0?-1:1;
}
bool operator ==(const point &a,const point &b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
double dot(point A,point B) { return A.x*B.x+A.y*B.y;}
double Cross(point A,point B) { return A.x*B.y-A.y*B.x;}
double Length(point A) {return sqrt(dot(A,A));}
bool isCross(point s1,point e1,point s2,point e2)///判断两次跨立相交,线段相交判定
{
///第一步,快速排斥实验
if(!(min(s1.x,e1.x)<=max(s2.x,e2.x)&&min(s2.x,e2.x)<=max(s1.x,e1.x)&&
min(s1.y,e1.y)<=max(s2.y,e2.y)&&min(s2.y,e2.y)<=max(s1.y,e1.y))) return false;
///首先判断向量s2e2 跨立 向量s1e1
double c1=Cross(s2-s1,e1-s1),c2=Cross(e1-s1,e2-s1);
///再次判断向量s1e1 跨立 向量 s2e2
double c3=Cross(s1-s2,e2-s2),c4=Cross(e2-s2,e1-s2);
///==0表示,相交于端点也认定为相交
if(dcmp(c1*c2)>0&&dcmp(c3*c4)>0) return true;
return false;
}
vector <pair<int,double> > G[maxn]; ///存储图
int vis[maxn],tot,Start,End;///SPFA
double dis[maxn];
point p[maxn]; ///存储点
void SPFA()
{
for(int i=1;i<=tot;i++) dis[i]=1000;
memset(vis,0,sizeof(vis));
// printf("%.2f\n",dis[End]);
queue<int> Q;
Q.push(Start);
vis[Start]=1;dis[Start]=0;
while(!Q.empty())
{
int u=Q.front();
Q.pop();
vis[u]=0;
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i].first;
double w=G[u][i].second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]) {
Q.push(v);
vis[v]=1;
}
}
}
}
}
int main()
{
int n;
while(~scanf("%d",&n)&&n!=-1)
{
tot=0;
p[tot++]=point(0,5);
double x,y1,y2,y3,y4;
for(int i=1;i<=n;i++)
{
scanf("%lf%lf%lf%lf%lf",&x,&y1,&y2,&y3,&y4);
p[tot++]=point(x,y1);
p[tot++]=point(x,y2);
p[tot++]=point(x,y3);
p[tot++]=point(x,y4);
}
p[tot++]=point(10,5);
for(int i=0;i<=tot;i++) G[i].clear();
for(int i=0;i<tot;i++) ///枚举点,start
{
for(int j=i+1;j<tot;j++) ///end
{
if(dcmp(p[i].x-p[j].x)==0) continue; ///两点都在同一块墙
bool flag=true;
for(int k=i+1;k<j;k++) ///判断有没有墙阻隔点(i,j)
{
if(dcmp(p[i].x-p[k].x)==0||dcmp(p[j].x-p[k].x)==0) ///阻隔墙不能在两点对应的墙
continue;
if(k%4==1){ ///第一块
if(isCross(p[i],p[j],p[k],point(p[k].x,0))){
flag=false;break;
}
}
else if(k%4==0){ ///第四块
if(isCross(p[i],p[j],p[k],point(p[k].x,10))){
flag=false;break;
}
}
else if(k%4==2){ ///第二块
if(isCross(p[i],p[j],p[k],p[k+1])){
flag=false;break;
}
}
else if(k%4==3){ ///第三块
if(isCross(p[i],p[j],p[k-1],p[k])){
flag=false;break;
}
}
}
if(flag) {
G[i].push_back(make_pair(j,Length(p[j]-p[i]))); ///建立双向边
G[j].push_back(make_pair(i,Length(p[j]-p[i])));
}
}
}
Start=0;End=tot-1; ///初始化
SPFA();
printf("%.2f\n",dis[End]);
}
return 0;
}
/*
i=0,j=1
i=0,j=2
i=0,j=3
i=0,j=4
i=0,j=5
i=1,j=5
i=2,j=5
i=3,j=5
i=4,j=5
i=0,j=1
i=0,j=2
i=0,j=3
i=0,j=4
i=0,j=5
i=0,j=6
i=0,j=7
i=0,j=8
i=1,j=5
i=1,j=6
i=1,j=7
i=1,j=8
i=1,j=9
i=2,j=5
i=2,j=6
i=2,j=7
i=2,j=8
i=2,j=9
i=3,j=5
i=3,j=6
i=3,j=7
i=3,j=8
i=3,j=9
i=4,j=5
i=4,j=6
i=4,j=7
i=4,j=8
i=4,j=9
i=5,j=9
i=6,j=9
i=7,j=9
i=8,j=9
*/