[计算几何][spfa] Jzoj P3856 规避

Description

2014年7月17日,马来西亚航空MH17班机执飞阿姆斯特丹史基浦机场飞往吉隆坡国际机场航线时,在乌克兰靠近俄罗斯边界33,000英尺高空疑受到9K37山毛榉地对空导弹击落坠毁。事件发生后,汉莎航空、法国航空、土耳其航空、俄罗斯洲际航空、达美航空、英国航空、俄罗斯航空、印度航空、捷特航空和荷兰皇家航空开始禁止班机进入乌克兰东部或全境领空范围。美国航空公司的班机禁止在乌克兰境内飞行,同时UTair航空、意大利航空和维珍航空也宣布他们的班机将会重新规划航行的路线。英国交通部已经要求该国的班机不要进入乌克兰领空范围。中国民用航空局已要求国内航空公司所有飞越乌克兰的航班绕飞。
作为相关负责人,你需要根据实际情况规划航线规避不安全地区,包括战争区域、危险天气、火山灰和外星人入侵……等。每个不安全区域被标记为一个凸多边形,每个凸多边形相离,你需要规划一条从指定起点到指定终点的航线,要求航线不得进入不安全区域,输出它的最短长度。为了你的方便,起点和终点都是多边形的顶点。
 

Input

第一行一个整数N表示不安全区域的数目。
接下来共N组描述,分别对应每个区域,首先输入一个空行,接下来第一个数num表示该区域顶点数,接下来共num个整数对按逆时针方向描述每个顶点。
在描述起点终点前输入空行,然后两个整数S和T描述起点和终点。起点为之前读入的总第S个顶点,终点同理。

Output

一行共一个数表示最短长度,保留4位小数。
 

Sample Input

2
 
4
0 0
1 0
1 1
0 1
 
4
2 2
3 2
3 3
2 3
 
1 7

Sample Output

4.8284
 

Data Constraint

M表示顶点总数   
对于10%的数据,N=1。
对于30%的数据,N<=2。
对于50%的数据,N<=10,M<=50。
对于100%的数据,N<=100,M<=300,-32768<=读入的坐标<=32767。

题解

  • 题目大意:在一个平面上有n个凸边形障碍物,问在不与障碍物相交的情况下,从起点到总点的最短距离
  • 看到这题,我们显然可以发现,一条最短路径应该是贴着凸边形走的,也就是在凸边形的边上走
  • 那么,我们就可以预处理出凸边形所有顶点两两的距离,然后要判断这条边有没有和凸边形相交
  • 怎么判断呢,这就是好问题
  • 每次判断是否与多边形隔一个点的两个点连成的弦判相交即可
  • 那么最后怎么求答案呢,其实随便跑个最短路算法就好了

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cmath>
 7 #define sqr(x) ((x)*1ll*(x))
 8 #define N 310
 9 #define M 180010
10 #define inf 1000000000.0 
11 #define fi first
12 #define se second
13 using namespace std;
14 typedef pair<int,int> edge;
15 struct Edge{ int to,from; double v; }e[M];
16 struct node{ edge x,y; }E[M];
17 int n,cnt,num[N],head[N],tot,k,s,t,l,vis[N];
18 double dis[N];
19 edge a[N];
20 double calc(edge a,edge b) { return sqrt(sqr(a.fi-b.fi)+sqr(a.se-b.se)); }
21 void insert(int x,int y,double v) 
22 { 
23     e[++cnt].to=y,e[cnt].from=head[x],e[cnt].v=v,head[x]=cnt; 
24     e[++cnt].to=x,e[cnt].from=head[y],e[cnt].v=v,head[y]=cnt; 
25 }
26 double cross(edge a,edge b,edge c) { return (a.fi-b.fi)*1.0*(a.se-c.se)-(a.se-b.se)*1.0*(a.fi-c.fi);}
27 bool checkcross(node a,node b){ return cross(a.x,a.y,b.x)*cross(a.x,a.y,b.y)<=1e-5&&cross(b.x,b.y,a.x)*cross(b.x,b.y,a.y)<=1e-5; }
28 bool check(edge a,edge b)
29 {
30     for (int i=1;i<=tot;i++)
31     {
32         if (E[i].x==a||E[i].y==b||E[i].x==b||E[i].y==a) continue;
33         if (checkcross((node){a,b},E[i])) return 0;
34     }
35     return 1;
36 }
37 double spfa()
38 {
39     queue<int> Q;
40     for (int i=1;i<=k;i++) dis[i]=inf;
41     dis[s]=0,Q.push(s);
42     while (!Q.empty())
43     {
44         int x=Q.front(); Q.pop(),vis[x]=0;
45         for (int i=head[x];i;i=e[i].from)
46             if (dis[e[i].to]>dis[x]+e[i].v)
47             {
48                 dis[e[i].to]=dis[x]+e[i].v;
49                 if (!vis[e[i].to]) vis[e[i].to]=1,Q.push(e[i].to);
50             }
51     }
52     return dis[t];
53 }
54 int main()
55 {
56     scanf("%d",&n);
57     for (int i=1;i<=n;i++)
58     {
59         scanf("%d",&num[i]),num[i]+=k;
60         for (int j=k+1;j<=num[i];j++)
61         {
62             scanf("%d%d",&a[j].fi,&a[j].se);
63             if (j-k!=1) insert(j,j-1,calc(a[j],a[j-1])),E[++tot]=(node){a[j],a[j-1]};
64         }
65         insert(k+1,num[i],calc(a[k+1],a[num[i]])),E[++tot]=(node){a[k+1],a[num[i]]},k=num[i];
66     }
67     for (int i=1;i<=k;i++)
68     {
69         while (i>num[l]) l++;
70         for (int j=i+1;j<=k;j++)
71         {
72             if (num[l-1]<j&&j<=num[l]) continue;
73             if (check(a[i],a[j])) insert(i,j,calc(a[i],a[j]));
74         }
75     }
76     scanf("%d%d",&s,&t),printf("%.4lf",spfa());
77 }
原文地址:https://www.cnblogs.com/Comfortable/p/10302312.html