计蒜客习题:迷阵突围
2018-03-10 23:15
204 查看
问题描述
蒜头君陷入了坐标系上的一个迷阵,迷阵上有 n 个点,编号从 1 到 n。蒜头君在编号为 1 的位置,他想到编号为 n 的位置上。蒜头君当然想尽快到达目的地,但是他觉得最短的路径可能有风险,所以他会选择第二短的路径。现在蒜头君知道了 n 个点的坐标,以及哪些点之间是相连的,他想知道第二短的路径长度是多少。注意,每条路径上不能重复经过同一个点。
输入格式
第一行输入两个整数 n (1≤n≤200) 和 m,表示一共有 n 个点和 m 条边。
接下来输入 n 行,每行输入两个整数xi,yi(−500≤xi,yi≤500),代表第 ii 个点的坐标。
接下来输入 mm 行,每行输入两个整数 pj,qj(1≤pj,qj≤n),表示点pj和点 qj之间相连。
输出格式
输出一行,输出包含一个数,表示第二短的路径长度(小数点后面保留两位),如果第一短路径有多条,则答案就是第一最短路径的长度;如果第二最短路径不存在,则输出 −1。
样例输入
3 3
1 1
2 2
3 2
1 2
2 3
1 3
样例输出
2.41
AC代码
原文传送门#include<iostream> #include<cstdio> #include<set> #include<vector> #include<cmath> #include<cstring> using namespace std; const int maxn=207; const int maxm=50007; //207*207 可能有重边 所以再开大一些 不给数据范围是真的睿智 int n,m; int x[maxn],y[maxn],fa[maxn],q[maxn]; double W(int u,int v); struct edge{ int v,nxt; double w; }e[maxm<<1]; //睿智了 打成了maxn int p[maxn],eid; double dist[maxn]; double ans=99999999; bool vst[maxn]; //int id[maxn][maxn]; typedef pair<double,int> pdi; set<pdi,less<pdi> >min_heap; void dijkstra(int a,int b); void ins(int u,int v); void ins2(int u,int v); void init(); int main(){ cin>>n>>m; init(); for(int i=1;i<=n;i++) cin>>x[i]>>y[i]; for(int i=1;i<=m;i++) { int a,b; cin>>a>>b; ins2(a,b); } int now=n; dijkstra(-1,-1); while(fa[now]){ dijkstra(fa[now],now); ans=min(dist ,ans); now=fa[now]; } if(ans==99999999) printf("-1"); else printf("%.2lf",ans); return 0; } double W(int u,int v){return sqrt((x[u]-x[v])*(x[u]-x[v])+(y[u]-y[v])*(y[u]-y[v]));} void dijkstra(int a,int b){ memset(vst,false,sizeof(vst)); for(int i=1;i<=n;i++) dist[i]=99999999; dist[1]=0; min_heap.insert(make_pair(0,1)); for(int i=1;i<=n;i++){ if(min_heap.size()==0) break; auto iter=min_heap.begin(); int v=iter->second; min_heap.erase(*iter); if(vst[v]) continue; vst[v]=true; for(int j=p[v];j;j=e[j].nxt){ //枚举相邻边 if(v==a&&e[j].v==b||v==b&&e[j].v==a) continue; //跳过最短路上的某条边 int x=e[j].v; if(dist[x]>dist[v]+e[j].w){ min b299 _heap.erase(make_pair(dist[x],x)); dist[x]=dist[v]+e[j].w; min_heap.insert(make_pair(dist[x],x)); if(a==-1&&b==-1) fa[x]=v; } } } } void ins(int u,int v){ e[++eid].v=v; e[eid].nxt=p[u]; e[eid].w=W(u,v); p[u]=eid; //eid要从1开始 0开始会炸 } void ins2(int u,int v){ins(u,v);ins(v,u);} //无向边插两次 void init(){ eid=0; memset(p,0,sizeof(p)); }