Gym 100625D 已知一条边追踪游人-最短路径-(两次dijkstra算法)

来源:互联网 发布:java实现文件上传下载 编辑:程序博客网 时间:2024/05/01 10:58

题意:有一群人在图上行走,这群人只走最短路径,你知道图的结构、他们的起点和几个给定的终点,还知道一条他们经过了的边M,现在通过这条边在给定的终点中找出他们可能的终点。

分析:

首先得会最短路径算法。dijkstra:单源节点到所有节点的最短路径;floyd:图上任意两个点的最短路径。这题用dijkstra算法。

本题抽象出来的意思就是给定的几个终点中有哪些的最短路径经过了已知边M。

方法是这样的:第一遍dijkstra算出起点S到每个点的最短路,然后以M的外源点(离S更远的那个点)为起点再用一次dijkstra,那么我们就得到了两个距离:dis1[],dis2[]。后面就是一个加法了。如果dis1[x]=dis1[h]+dis[x]那么终点x的最短路肯定经过了已知边。也就是起点到终点的最短路==起点到转折点的最短路+转折点到终点的最短路,很好理解吧。

外源点不就是离起点远的那个吗,所以:if(dis1[g]>dis1[h])  swap(g,h)

代码:

#include<map>#include<cstdio>#include<vector>#include<algorithm>#include<iostream>#include<set>#include<cstdlib>#include<cstring>#include<queue>#define INF 1000000007using namespace std;int vis[2005],w[2005][2005];int dis[2005],dis2[2005];int t,n,m,k,s,g,h;int ans[2005];void dijkstra(int s){memset(vis,0,sizeof(vis));vis[s]=1;for(int i=1;i<=n;i++) dis[i]=w[s][i];dis[s]=0;for(int i=1;i<=n;i++){int u,mi=INF;for(int j=1;j<=n;j++){if(!vis[j]&&dis[j]<mi){mi=dis[j];u=j;}}vis[u]=1;for(int j=1;j<=n;j++){if(!vis[j]&&w[j][u]!=INF){dis[j]=min(dis[j],w[j][u]+dis[u]);}}}}int main(){scanf("%d",&t);while(t--){scanf("%d%d%d",&n,&m,&k);scanf("%d%d%d",&s,&g,&h);for(int i=0;i<=n;i++)for(int j=0;j<=n;j++) w[i][j]=INF;while(m--){int a,b,c;scanf("%d%d%d",&a,&b,&c);w[a][b]=w[b][a]=c;}dijkstra(s);for(int i=1;i<=n;i++) dis2[i]=dis[i];if(dis[g]>dis[h]) swap(g,h);dijkstra(h);int cnt=0;while(k--){int x;scanf("%d",&x);if(dis2[x]==dis2[h]+dis[x]) ans[cnt++]=x;}sort(ans,ans+cnt);for(int i=0;i<cnt-1;i++) printf("%d ",ans[i]);printf("%d\n",ans[cnt-1]);}}


0 0
原创粉丝点击