寻找两条最短路的公共路径
寻找两条最短路的公共路径
[SDOI2009] Elaxia的路线
题目描述
最近,Elaxia 和 w** 的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们必须合理地安排两个人在一起的时间。
Elaxia 和 w** 每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。
现在已知的是 Elaxia 和 w** 所在的宿舍和实验室的编号以及学校的地图:
地图上有 \(n\) 个路口,\(m\) 条路,经过每条路都需要一定的时间。 具体地说,就是要求无向图中,两对点间最短路的最长公共路径。
输入格式
第一行两个正整数 \(n,m\),表示点数和边数。
第二行四个正整数 \(x_1,y_1,x_2,y_2\),分别表示 Elaxia 的宿舍和实验室及 w** 的宿舍和实验室的标号。
接下来 \(m\) 行,每行三个整数 \(u,v,w\),表示 \(u,v\)之间有一条边,需要 \(w\) 的时间经过。
输出格式
一行一个整数表示答案。(即最长公共路径的长度)
样例 #1
样例输入 #1
9 10 1 6 7 8 1 2 1 2 5 2 2 3 3 3 4 2 3 9 5 4 5 3 4 6 4 4 7 2 5 8 1 7 9 1
样例输出 #1
3
提示
【数据范围】
对于 \(30\%\) 的数据,\(1\le n \le 100\);
对于 \(60\%\) 的数据,\(1\le n \le 1000\);
对于 \(100\%\) 的数据,\(1\le n \le 1500\),\(1 \leq m \leq 3 \times 10^5\),\(1\le w \le 10^4\),输入数据保证没有重边和自环。
#include<bits/stdc++.h> using namespace std; const int N=2010; struct edge{ int v,nxt; int w; }e1[N*N],e2[N*N]; struct Node{ int dis,u; bool operator<(const Node &a) const{ return a.dis<dis; } }; int cnt1,cnt2,head1[N],head2[N],ans; int dis[5][N],in[N],len[N],vis[N]; int n,m,pos1,pos2,pos3,pos4; void add1(int u,int v,int w){ e1[cnt1].w=w; e1[cnt1].v=v; e1[cnt1].nxt=head1[u]; head1[u]=cnt1++; } void add2(int u,int v,int w){ in[v]++; e2[cnt2].w=w; e2[cnt2].v=v; e2[cnt2].nxt=head2[u]; head2[u]=cnt2++; } void dijkstra(int id,int s){ priority_queue<Node> pq; memset(vis,0,sizeof(vis)); memset(dis[id],0x3f,sizeof(dis[id])); pq.push((Node){0,s}); dis[id][s]=0; while(!pq.empty()){ int u=pq.top().u; int d=pq.top().dis;; pq.pop(); if(vis[u]) continue; vis[u]=1; for(int i=head1[u];i+1;i=e1[i].nxt){ int v=e1[i].v; if(vis[v]) continue; if(dis[id][v]>d+e1[i].w){ dis[id][v]=d+e1[i].w; pq.push((Node){dis[id][v],v}); } } } } void tuopu(){ queue<int> q; for(int i=1;i<=n;i++){ if(!in[i]) q.push(i); } while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head2[u];i+1;i=e2[i].nxt){ int v=e2[i].v; len[v]=max(len[v],len[u]+e2[i].w); if(--in[v]==0) q.push(v); } } } int main(){ memset(head1,-1,sizeof(head1)); scanf("%d%d%d%d%d%d",&n,&m,&pos1,&pos2,&pos3,&pos4); for(int i=1;i<=m;i++){ int u,v,w; scanf("%d%d%d",&u,&v,&w); add1(u,v,w); add1(v,u,w); } dijkstra(1,pos1);dijkstra(2,pos2); dijkstra(3,pos3);dijkstra(4,pos4); memset(head2,-1,sizeof(head2)); for(int u=1;u<=n;u++){ for(int i=head1[u];i+1;i=e1[i].nxt){ int v=e1[i].v; if(dis[1][u]+e1[i].w+dis[2][v]==dis[1][pos2]&& dis[3][u]+e1[i].w+dis[4][v]==dis[3][pos4]) add2(u,v,e1[i].w); } } tuopu(); for(int i=1;i<=n;i++) ans=max(ans,len[i]); memset(in,0,sizeof(in)); memset(len,0,sizeof(len)); memset(head2,-1,sizeof(head2)); cnt2=0; for(int u=1;u<=n;u++){ for(int i=head1[u];i+1;i=e1[i].nxt){ int v=e1[i].v; if(dis[1][u]+e1[i].w+dis[2][v]==dis[1][pos2]&& dis[4][u]+e1[i].w+dis[3][v]==dis[3][pos4]) add2(u,v,e1[i].w); } } tuopu(); for(int i=1;i<=n;i++) ans=max(ans,len[i]); printf("%d",ans); return 0; }
最关键的部分即为这一段
for(int u=1;u<=n;u++){ for(int i=head1[u];i+1;i=e1[i].nxt){ int v=e1[i].v; if(dis[1][u]+e1[i].w+dis[2][v]==dis[1][pos2]&& dis[3][u]+e1[i].w+dis[4][v]==dis[3][pos4]) add2(u,v,e1[i].w); } }
跑过四遍最短路后,即可得到一个点到其他点的距离,因为Elaxia和w**的路线都有多条最短路,然后就可以枚举每条边,把属于两种路线中最短路共有的部分找出来,建一张图,然后对图进行拓扑排序,就可得到最长公共路径。
本文作者:imfbustxhf
本文链接:https://www.cnblogs.com/imfbustxhf/p/18526084
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步