[计算几何][spfa] Jzoj P3856 规避
题解
- 题目大意:在一个平面上有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 }