牛客国庆集训派对Day1 L New Game!(堆优化dijkstra+建图)
链接:https://ac.nowcoder.com/acm/contest/201/L
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
Special Judge, 64bit IO Format: %lld
空间限制:C/C++ 1048576K,其他语言2097152K
Special Judge, 64bit IO Format: %lld
题目描
Eagle Jump公司正在开发一款新的游戏。Hifumi Takimoto作为其中的员工,获得了提前试玩的机会。现在她正在试图通过一个迷宫。
这个迷宫有一些特点。为了方便描述,我们对这个迷宫建立平面直角坐标系。迷宫中有两条平行直线 L1:Ax+By+C1=0, L2:Ax+By+C2=0,还有 n 个圆 Ci:(x−xi)2+(y−yi)2=ri2Ci:(x−xi)2+(y−yi)2=ri2。角色在直线上、圆上、园内行走不消耗体力。在其他位置上由S点走到T点消耗的体力为S和T的欧几里得距离。
Hifumi Takimoto想从 L1 出发,走到 L2 。请计算最少需要多少体力。
输入描述:
第一行五个正整数 n,A,B,C1,C2(1≤ n ≤ 1000, -10000 ≤ A,B,C1,C2≤ 10000),其中 A,B 不同时为 0。
接下来 n 行每行三个整数 x,y,r(-10000 ≤ x,y ≤ 10000, 1≤ r ≤ 10000) 表示一个圆心为 (x,y),半径为 r 的圆。
输出描述:
仅一行一个实数表示答案。与正确结果的绝对误差或者相对误差不超过 10-4
即算正确。
示例1
输入
2 0 1 0 -4 0 1 1 1 3 1
输出
0.236068
题目大意:
给你两条平行的直线,n个圆,在直线和圆上运动不需要能量(距离),问从一条直线到另一条直线最少需要多少距离。
从一条直线到另一条直线,一共可能经过三种路径。
直线到直线,直线到圆,圆到圆,都是无向边。
这三种分别有1,2n,n^2条边,注意链式前向星开空间需要乘2。
以后最好还是用dijkstra的堆优化版本吧,spfa被卡了。
总结一下各种最短路算法的适用条件(V为点数,E为边数):
Floyd:V^3
Spfa:平均kE(一般k为小常数2,表示每个点平均进队次数) 最差VE 可见稠密图卡爆,故若正权图就用dijkstra吧,只有负权图用spfa
Dijkstra:普通V^2 堆优化ElogV 可见稠密图上普通版,其他只要都上堆优化版,不过只适用于正权图的情况
还涉及到一点计算几何。要入门计算几何了嘛?233
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <string> #include <cmath> #include <queue> #include <deque> #include <stack> #include <map> #include <set> typedef long long ll; const double eps=1e-5; const int mod=1000000007; const double inf=10000000000; const int maxn=2000; const int maxm=100000; using namespace std; struct tcircle { double x,y,r; }; tcircle cir[maxn+10]; double dotdot(double x1,double y1,double x2,double y2) { return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); } double dotline(double x,double y,double a,double b,double c) { return fabs(a*x+b*y+c)/sqrt(a*a+b*b); } double lineline(double a,double b,double c1,double c2) { return fabs(c1-c2)/sqrt(a*a+b*b); } int to[(maxn+10)*(maxn+10)+10]; double w[(maxn+10)*(maxn+10)+10]; int nex[(maxn+10)*(maxn+10)+10]; int head[maxn+10],cnt=0; void addedge(int u,int v,double wei) { to[cnt]=v;w[cnt]=wei; nex[cnt]=head[u];head[u]=cnt++; to[cnt]=u;w[cnt]=wei; nex[cnt]=head[v];head[v]=cnt++; } struct tnode { double d; int u; bool operator<(const tnode& rhs) const { return d>rhs.d; } }; double dis[maxn+10]; int done[maxn+10]; int main() { int n; double a,b,c1,c2; scanf("%d%lf%lf%lf%lf",&n,&a,&b,&c1,&c2); for(int i=1;i<=n;i++) scanf("%lf%lf%lf",&cir[i].x,&cir[i].y,&cir[i].r); memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { double d=dotdot(cir[i].x,cir[i].y,cir[j].x,cir[j].y); if(d>cir[i].r+cir[j].r) addedge(i,j,d-cir[i].r-cir[j].r); else addedge(i,j,0); } } for(int i=1;i<=n;i++) { double d; d=dotline(cir[i].x,cir[i].y,a,b,c1); if(d>cir[i].r) addedge(i,n+1,d-cir[i].r); else addedge(i,n+1,0); d=dotline(cir[i].x,cir[i].y,a,b,c2); if(d>cir[i].r) addedge(i,n+2,d-cir[i].r); else addedge(i,n+2,0); } addedge(n+1,n+2,lineline(a,b,c1,c2)); for(int i=1;i<=n+2;i++) dis[i]=inf; dis[n+1]=0; memset(done,0,sizeof(done)); priority_queue<tnode> q; q.push((tnode){0,n+1}); while(!q.empty()) { tnode x=q.top();q.pop(); int u=x.u; if(done[u]) continue; done[u]=1; for(int i=head[u];i!=-1;i=nex[i]) { int l=to[i]; if(dis[l]>dis[u]+w[i]) { dis[l]=dis[u]+w[i]; q.push((tnode){dis[l],l}); } } } printf("%f\n",dis[n+2]); return 0; }