返回顶部

P1629 邮递员送信

 

原题传送锚点

又是一道水题。

题目描述

有一个邮递员要送东西,邮局在节点 1。他总共要送 n1 样东西,其目的地分别是节点 2 到节点 n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n1 样东西并且最终回到邮局最少需要的时间。

输入格式

第一行包括两个整数,n 和 m,表示城市的节点数量和道路数量。

第二行到第 (m+1) 行,每行三个整数,u,v,w,表示从 u 到 v 有一条通过时间为 w 的道路。

输出格式

输出仅一行,包含一个整数,为最少需要的时间。

输入输出样例

输入 #1
5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2
输出 #1
83

说明/提示

对于 30% 的数据,1n200。

对于 100% 的数据,1n1031m1051u,vn,1w104,输入保证任意两点都能互相到达。

开始日常水题解:

分析题意:邮递员从结点1出发,每次携带一样东西,直到将n-1样东西分别送到除1之外的n-1个结点后返回结点1,求总路径所花的最小时间。

若不计返回,邮递员将东西送往n-1个结点时间最少,典型的单源最短路,可用Dijkstra求出所有最短距后相加。

但问题是:这是个有向图,邮递员每次送完东西后都要返回结点1,他可不敢在单行道上逆行。

怎么办呢?从每个结点出发求到结点1的最短距?

或许我们可以动用一下逆向思维。

从每个结点出发到结点1的最短距也可以转化为结点1到每个结点的最短距。

怎么实现呢?反向建边嘛。

我们不妨再建一张图,这张图所有的边方向都与原图相反,此时再跑一边Dijkstra就可以了。

Code:

复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,tot1,tot2,ans;
int d1[N],fi1[N],ne1[N*2],to1[N*2],w1[N*2];
int d2[N],fi2[N],ne2[N*2],to2[N*2],w2[N*2];
bool vis1[N],vis2[N];
priority_queue<pair<int,int> > q1,q2;

void add1(int x,int y,int z)
{
    ne1[++tot1]=fi1[x];
    fi1[x]=tot1;
    to1[tot1]=y;
    w1[tot1]=z;
}

void add2(int x,int y,int z)
{
    ne2[++tot2]=fi2[x];
    fi2[x]=tot2;
    to2[tot2]=y;
    w2[tot2]=z;
}

void dfs()
{
    memset(d1,0x7f,sizeof(d1));
    memset(d2,0x7f,sizeof(d2));
    d1[1]=0,d2[1]=0;
    q1.push(make_pair(0,1));
    q2.push(make_pair(0,1));
    while(!q1.empty())
    {
        int x=q1.top().second;
        q1.pop();
        if(vis1[x]) continue;
        vis1[x]=1;
        for(int i=fi1[x];i;i=ne1[i])
        {
            int v=to1[i];
            if(d1[v]>d1[x]+w1[i])
            {
                d1[v]=d1[x]+w1[i];
                q1.push(make_pair(-d1[v],v));
            }
        }
    }
    while(!q2.empty())
    {
        int x=q2.top().second;
        q2.pop();
        if(vis2[x]) continue;
        vis2[x]=1;
        for(int i=fi2[x];i;i=ne2[i])
        {
            int v=to2[i];
            if(d2[v]>d2[x]+w2[i])
            {
                d2[v]=d2[x]+w2[i];
                q2.push(make_pair(-d2[v],v));
            }
        }
    }
}

int main()
{
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        add1(x,y,z),add2(y,x,z);
    }
    dfs();
    for(int i=1;i<=n;i++)
        ans+=d1[i]+d2[i];
    cout<<ans<<'\n'; 
}
复制代码

 

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   光暗之影x  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示