题意:
k条直线,不能越过直线,从起点到终点最短距离是多少。
思路:
对每个直线上的点加上起点终点,如果两点的直线不与其他直线有交点,那么就建边。
之后dij算出到每个点的最短距离即可。
tips:
两条直线AB,CD,要判断AB是否与CD相交,只需要判断A,B是否在CD两侧,且C,D是否在AB两侧。
则有 ABAC与ABAD异号(向量叉乘),CDCA与CDCB异号。
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int maxn = 1000 + 7;
const double eps = 1e-6;
int n,m,k;
vector<pair<int,double> >G[maxn];
struct Point {
double x,y;
Point(){
}
Point(double x,double y) {
this -> x = x;
this -> y = y;
}
Point operator+(Point a)
{
return Point(x + a.x,y + a.y);
}
Point operator-(Point a)
{
return Point(x - a.x,y - a.y);
}
Point operator*(double t)
{
return Point(x * t,y * t);
}
double operator*(Point a)
{
return x * a.y - y * a.x;
}
Point operator/(double t)
{
return Point(x / t,y / t);
}
double operator^(Point a)
{
return x * a.x + y * a.y;
}
double vl()
{
return sqrt(x * x + y * y);
}
}sta,ed;
double dis(Point p1,Point p2) {
return sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
struct Line {
Point a,b;
Line(){
};
Line(Point a,Point b) {
this -> a = a;
this -> b = b;
}
double Len() {
return dis(a,b);
}
}a[maxn];
Point Intersection(Line X,Line Y) {
//算直线交点
Point v = X.a - X.b;
Point w = Y.a - Y.b;
Point u = X.a - Y.a;
double t = (w * u) / (v * w);
return X.a + v * t;
}
int same(double x,double y) {
if(fabs(x - y) < eps) return true;
return false;
}
int sign(double x) {
if(x < -eps) {
return -1;
} else if(x > eps) return 1;
return 0;
}
bool judge(Line line) {
//是否和其他直线有交点,且交点不是端点,判断线段是否相交
for(int i = 1;i <= k;i++) {
Point AD = line.a - a[i].a;
Point AC = line.a - a[i].b;
Point AB = line.a - line.b;
Point CA = a[i].a - line.a;
Point CB = a[i].a - line.b;
Point CD = a[i].a - a[i].b;
if((CD * CA) * (CD * CB) < 0 && (AB * AC) * (AB * AD) < 0) {
return true;
}
}
return false;
}
int head[maxn],nex[maxn * maxn],to[maxn * maxn],tot;
double val[maxn * maxn];
void add(int x,int y,double z) {
to[++tot] = y;
nex[tot] = head[x];
val[tot] = z;
head[x] = tot;
to[++tot] = x;
nex[tot] = head[y];
val[tot] = z;
head[y] = tot;
}
double d[maxn];
int vis[maxn];
void dij() {
priority_queue<pair<double,int> >q;
q.push({
0,0});
for(int i = 0;i < maxn;i++) d[i] = 1e18;
d[0] = 0;
while(!q.empty()) {
pair<double,int> now = q.top();q.pop();
int x = now.second;
if(vis[x]) continue;
vis[x] = 1;
for(int i = head[x];i;i = nex[i]) {
int v = to[i];
double w = val[i];
if(d[v] > d[x] + w) {
d[v] = d[x] + w;
q.push({
-d[v],v});
}
}
}
}
int main() {
scanf("%d%d%d",&n,&m,&k);
vector<Point>vec;
for(int i = 1;i <= k;i++) {
Point p1,p2;
scanf("%lf%lf%lf%lf",&p1.x,&p1.y,&p2.x,&p2.y);
a[i].a = p1;a[i].b = p2;
}
scanf("%lf%lf%lf%lf",&sta.x,&sta.y,&ed.x,&ed.y);
vec.push_back(sta);
for(int i = 1;i <= k;i++) {
vec.push_back(a[i].a);
vec.push_back(a[i].b);
add(vec.size() - 2,vec.size() - 1,a[i].Len());
}
vec.push_back(ed);
for(int i = 0;i < vec.size();i++) {
for(int j = i + 1;j < vec.size();j++) {
//从i到j建边
Line line = Line(vec[i],vec[j]);
double len = dis(vec[i],vec[j]);
if(!judge(line)) {
add(i,j,len);
// printf("%d %d\n",i,j);
}
}
}
dij();
printf("%.4f\n",d[vec.size() - 1]);
return 0;
}