P1629 邮递员送信

Posted lisiyuwang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1629 邮递员送信相关的知识,希望对你有一定的参考价值。

 

题目描述

有一个邮递员要送东西,邮局在节点 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;
}

 

 

 

以上是关于P1629 邮递员送信的主要内容,如果未能解决你的问题,请参考以下文章

P1629 邮递员送信

洛谷 P1629 邮递员送信

P1629 邮递员送信(正反向建图 or 暴力)

P1629 邮递员送信

洛谷—— P1629 邮递员送信

P1629 邮递员送信(未完成)