题意:给定你k条线段的端点坐标,这k条线段相当于k道墙,小米机器人无法穿过每堵墙,但是可以沿着墙行走,然后给定你一个起始点坐标和终点坐标,问你从起点到终点最短的距离是多少即可。
思路:很明显假如没有墙的限制,那就是个裸的最短路,加上了墙的限制,就是对我们能够建边的点加上了限制。在这个题中,我们只需要把起点和终点再加上每条线段的端点放入一个vector中,然后枚举两个点形成的线段和其他所有的线段墙,只要他们之间不存在交点或者交点在端点处,这时枚举的两个点就可以建边,建完边后跑一遍最短路即可以解决问题了。
判断两条线段有没有交点,很明显我们要用叉积来判断。
加点的时候先加起点,最后加终点,并且每条线段的两个端点之间是一定要建上边的。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-9;
const int MAXN = 1007;
const int inf = 0x3f3f3f3f;
int sign(double x)//判断符号可用
{
if(fabs(x) <= eps) return 0;
if(x > 0) return 1;
else return -1;
}
struct Point
{
double x,y;
Point(){}
//定义运算
Point(double _x,double _y){x = _x;y = _y;}
Point operator + (const Point &b)const{
return Point(x+b.x,y+b.y);
}
Point operator - (const Point &b)const{
return Point(x-b.x,y-b.y);
}
Point operator * (const double &k)const{//乘常数
return Point(x*k,y*k);
}
Point operator / (const double &k)const{
return Point(x/k,y/k);
}
//点的叉积和点积都是数
//点积
double operator * (const Point &b)const{
return x*b.x+y*b.y;
}
//叉积
double operator ^ (const Point &b)const{
return x*b.y-y*b.x;
}
double powlen(){return x*x+y*y;};
double len(){return sqrt(powlen());}
};
double cross(Point a,Point b){//叉积
return a.x*b.y-a.y*b.x;
}
double dot(Point a,Point b){//点积
return a.x*b.x+a.y*b.y;
}
double dis(Point a,Point b){
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
struct Line{
Point a,b;
Line(){};
Line(Point _a,Point _b){a = _a;b = _b;}
}line[MAXN];
int head[MAXN],cnt;
struct node{
int next,to;
double w;
}edge[MAXN*MAXN];
void addedge(int u,int v,double w){ edge[++cnt].to = v;edge[cnt].w = w;edge[cnt].next = head[u];head[u] = cnt; }
bool check(Line l1,Line l2){
Point AB = l1.b - l1.a;
Point AD = l2.b - l1.a;
Point AC = l2.a - l1.a;
Point CD = l2.b - l2.a;
Point CA = l1.a - l2.a;
Point CB = l1.b - l2.a;
if(sign(cross(AB,AC)) * sign(cross(AB,AD)) < 0 && sign(cross(CD,CA)) * sign(cross(CD,CB)) < 0 )
return true;
return false;
}
double d[MAXN];int vis[MAXN];
void spfa(int s){
d[s] = 0;
vis[s] = 1;
for(int i = 1;i < MAXN;i ++) d[i] = (double)inf;
queue<int>q;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u];i;i = edge[i].next){
int v = edge[i].to;
if(d[v] > d[u] + edge[i].w){
d[v] = d[u] + edge[i].w;
if(!vis[v]){
vis[v] = 1;
q.push(v);
}
}
}
}
}
vector<Point>v;
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int tot = 0;
for(int i = 1;i <= k;i ++){
Point p1,p2;
scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y);
line[i].a = p1,line[i].b = p2;
}
Point st,ed;
scanf("%lf%lf%lf%lf",&st.x,&st.y,&ed.x,&ed.y);
v.push_back(st);
for(int i = 1;i <= k;i ++){
v.push_back(line[i].a);
v.push_back(line[i].b);
int from = v.size()-2,to = v.size()-1;
double len = dis(v[from],v[to]);
//cout<<"---"<<len<<endl;
addedge(from,to,len);
addedge(to,from,len);
}
v.push_back(ed);
for(int i = 0;i < v.size();i ++){
for(int j = i + 1;j < v.size();j ++){
Line tmp = Line(v[i],v[j]);
int flag = 0;
for(int tt = 1;tt <= k;tt ++){
if(check(tmp,line[tt])){
flag = 1;
break;
}
}
if(!flag){
addedge(i,j,dis(v[i],v[j]));
addedge(j,i,dis(v[i],v[j]));
}
}
}
spfa(0);
printf("%.4f\n",d[v.size()-1]);
return 0;
}