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

浪里个浪

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);    //添加新的起点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);    //添加新的终点n+1
			path[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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值