标签:必须 size jks span style 优先 return 其他 open
有一个邮递员要送东西,邮局在节点 1。他总共要送 n-1 样东西,其目的地分别是节点 2 到节点 n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m条道路。
这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n-1 样东西并且最终回到邮局最少需要的时间。
第一行包括两个整数,n 和 m,表示城市的节点数量和道路数量。
第二行到第 (m+1) 行,每行三个整数,u,v,w,表示从 u到 v 有一条通过时间为 w 的道路。
输出仅一行,包含一个整数,为最少需要的时间。
分析:
该题初看是考察单源最短路径问题,第一反应,dijkstra,SPFA等均可,再仔细一看,居然还要从每个点再返回到点1,嗯?莫非是 Floyed?但看了看时间限制和所给的数据大小……要真这么干得死得透透的,
而且拆开来看,必要工作1是求从点1 到其他各点,这是个单源最短路径问题,必要工作2是从其他点反向求到点1,不需要将其他的点之间的距离求出,因此用多次dijkstra或SPFA的话时间和空间上会有很多浪费,
其实仔细一想,求从各点到点1,的最短距离,若回来的最短路不是单方向的,而是双向的,那么从这些点回来的总路径长度相当于沿着这些路径从点1到这些点的路径总长度,即依然是个单源最短路径问题,只不过
是将路反过来而已(如原来是 3->4 现在反向是4 -> 3)代码如下:
#include<iostream> #include<queue> #include<cstring> using namespace std; const int MAX = 1000009; const int MX = 1005; int first1[MX] = {0}; //正向边 int next1[MAX] = {0}; int first2[MX] = {0}; //反向边 int next2[MAX] = {0}; struct node{ int fr; int to; int w; }a[MAX],b[MAX]; struct nd{ int to; int w; bool operator <(const struct nd& a)const{ return a.w < w; } }; int spfa(int n,int m){ int min = 0; int dis[MX]; priority_queue<struct nd>q; q.push((struct nd){1,0}); memset(dis,MAX,sizeof(dis)); dis[1] = 0; while(!q.empty()){ int to; int w; to = q.top().to; w = q.top().w; q.pop() ; if(dis[to] != w ) continue; //优先队列的性质决定,可少用一个标记数组记录是否已经是最小dis,不懂的结合下面循环中的push 多想想 for(int i = first1[to];i != 0;i = next1[i]){ if(dis[a[i].to] > w + a[i].w ){ dis[a[i].to] = w + a[i].w ; q.push((struct nd){a[i].to,dis[a[i].to]}); } } } for(int i = 2;i <= n;i++) min += dis[i]; //反向 q.push((struct nd){1,0}); memset(dis,MAX,sizeof(dis)); dis[1] = 0; while(!q.empty()){ int to; int w; to = q.top().to; w = q.top().w; q.pop() ; if(dis[to] != w ) continue; for(int i = first2[to];i != 0;i = next2[i]){ if(dis[a[i].fr] > w + a[i].w ){ dis[a[i].fr] = w + a[i].w ; q.push((struct nd){a[i].fr,dis[a[i].fr]}); } } } for(int i = 2;i <= n;i++) min += dis[i]; return min; } int main(){ int n,m; //点数,边数 cin >> n >> m; for(int i = 1;i <= m;i++){ cin >> a[i].fr >> a[i].to >> a[i].w ; next1[i] = first1[a[i].fr]; first1[a[i].fr] = i; next2[i] = first2[a[i].to]; //边反向,使用时需要将 to的地位 //看做 fr,fr看做to first2[a[i].to ] = i; } int min = spfa(n,m); cout << min; return 0; }
标签:必须 size jks span style 优先 return 其他 open
原文地址:https://www.cnblogs.com/LISIYUWANG/p/13264139.html