当前位置: 代码迷 >> 综合 >> 浪里个浪 FZU - 2261 (多源最短路问题)
  详细解决方案

浪里个浪 FZU - 2261 (多源最短路问题)

热度:4   发布时间:2024-01-20 21:56:57.0

浪里个浪

TonyY是一个喜欢到处浪的男人,他的梦想是带着兰兰姐姐浪遍天朝的各个角落,不过在此之前,他需要做好规划。

现在他的手上有一份天朝地图,上面有n个城市,m条交通路径,每条交通路径都是单行道。他已经预先规划好了一些点作为旅游的起点和终点,他想选择其中一个起点和一个终点,并找出从起点到终点的一条路线亲身体验浪的过程。但是他时间有限,所以想选择耗时最小的,你能告诉他最小的耗时是多少吗?

Input

包含多组测试数据。

输入第一行包括两个整数n和m,表示有n个地点,m条可行路径。点的编号为1 - n。

接下来m行每行包括三个整数i, j, cost,表示从地点i到地点j需要耗时cost。

接下来一行第一个数为S,表示可能的起点数,之后S个数,表示可能的起点。

接下来一行第一个数为E,表示可能的终点数,之后E个数,表示可能的终点。

0<S, E≤n≤100000,0<m≤100000,0<cost≤100。

Output

输出他需要的最短耗时。

Sample Input

4 4
1 3 1
1 4 2
2 3 3
2 4 4
2 1 2
2 3 4

Sample Output

1

题意: 

这个题就是一个多源最短路的问题。多源最短路的问题可以转换为单源最短路:将所有的起点全部通过一个自己添加的初始点(比如 ‘0’点) 且0点到所有的起点的距离全部为0,然后再添加一个最终点n+1(默认有n个地点),来让所有的可以到达的终点到最终点n+1的距离全部为0,然后找从新起点‘0’到最终点‘n+1’的最短路。

这个题可以使用dijkstra和spfa,但是使用普通的dijkstra的话由于题目中给出的个数都比较大,所以会超时超内存,所以要用堆优化的dijkstra。

(堆优化的dijkstra与spfa是类似的,堆优化的dijkstra用了堆,每次都找出最短的路径来松弛每个边,一下子就可以松弛到最短路径;而spfa是将所有的点都放入队列,顺序来进行松弛,逐渐的趋近最短路)

堆优化的dijkstra算法:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<stdlib.h>
using namespace std;const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
struct Edge{int to;int val;bool operator < (const Edge& a)const   //重载运算符 ‘<’,变为最小堆{return val>a.val;}Edge(int a,int b):to(a),val(b){}Edge(){}
};
int dis[maxn]; //存放起点到达每个点的最短路
int vis[maxn];
int n,m;
vector<Edge>path[maxn];void dijkstra()
{memset(vis,0,sizeof(vis));memset(dis,inf,sizeof(dis));priority_queue<Edge> queue;dis[0]=0;queue.push(Edge(0,0));while(!queue.empty()){Edge tmp=queue.top();queue.pop();int a=tmp.to;if(vis[a]==1)continue;vis[a]=1;for(int i=0;i<path[a].size();i++){ int b=path[a][i].to;if(!vis[b]&&dis[b]>dis[a]+path[a][i].val){	dis[b]=dis[a]+path[a][i].val;Edge e=Edge(b,dis[b]);queue.push(e);}}}
}int main()
{while(scanf("%d%d",&n,&m)!=EOF){for(int i=0;i<=n;i++)path[i].clear();for(int i=0;i<m;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);Edge e=Edge(v,w);path[u].push_back(e);}int s,t;scanf("%d",&s);for(int i=0;i<s;i++){int start;scanf("%d",&start);Edge e=Edge(start,0);    //添加新的起点0path[0].push_back(e);}scanf("%d",&t);for(int i=0;i<t;i++){int end;scanf("%d",&end);Edge e=Edge(n+1,0);    //添加新的终点n+1path[end].push_back(e);}dijkstra();printf("%d\n",dis[n+1]);}return 0;
}

spfa算法:

#include<iostream>    
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<stdlib.h>
using namespace std;const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
struct Edge{int to;int val; Edge(int a,int b):to(a),val(b){}Edge(){}
};
int dis[maxn];
int vis[maxn];
int n,m;
vector<Edge>path[maxn];void dijkstra()
{memset(vis,0,sizeof(vis));for(int i=0;i<=n+1;i++)dis[i]=inf;dis[0]=0;queue<int>q;vis[0]=1;q.push(0);while(!q.empty()){int x=q.front();q.pop();for(int i=0;i<path[x].size();i++){int to=path[x][i].to;int val=path[x][i].val;if(dis[to]>dis[x]+val)dis[to]=dis[x]+val;if(!vis[to]){q.push(to);vis[to]=1;}}}
}int main()
{while(scanf("%d%d",&n,&m)!=EOF){for(int i=0;i<m;i++)path[i].clear();for(int i=0;i<m;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);Edge e=Edge(v,w);path[u].push_back(e);}int s,t;scanf("%d",&s);for(int i=0;i<s;i++){int start;scanf("%d",&start);Edge e=Edge(start,0);path[0].push_back(e);}scanf("%d",&t);for(int i=0;i<t;i++){int end;scanf("%d",&end);Edge e=Edge(n+1,0);path[end].push_back(e);}dijkstra();printf("%d\n",dis[n+1]);}return 0;
}