4.28 洛谷 P1629 邮递员送信

题目描述

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

输入格式

  • 第一行包括两个整数,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% 的数据, 1 ≤ n ≤ 200。
  • 对于 100% 的数据,1 ≤ n ≤ 103,1 ≤ m ≤ 105,1 ≤ u,v ≤ n,1 ≤ w ≤ 104
  • 输入保证任意两点都能互相到达。

思路

正常使用Dirskra最短路径遍历所有边更新起点到其他点的距离。但是因为本题还需要求返回起点的最短路径,并且因为边是单向的,不能原路返回,所以建议使用反向图,再求一下起点到各点的最短路径,既各点到起点的最短路径;

代码如下,详见注释

#include <iostream>
#include <cstdio>
#define MAX 1005

using namespace std;

int dis[MAX], drs[MAX], sum=0; 		//两个数组一个存初始点到其他点的最短距离,一个存其他点到初始点的距离; 
int u[MAX*100], v[MAX*100], w[MAX*100];	//注意数组大小,后面我才注意到是10^5,结果只有30分,卡了我贼久; 
int n, m, s, check, b1=1, b2=1;			//check用来检查dis[]和drs[]是否更新完; 
const int inf=0x3f3f3f3f;
int main()
{
    scanf("%d%d", &n, &m); 				//也可以用cin输入,应该没问题; 
    s = 1;
    for(int i=1;i<=m;i++)
        scanf("%d%d%d", &u[i], &v[i], &w[i]);
    for(int i=1;i<=n;i++)
        dis[i] = drs[i] = inf; 			//初始化dis[]和drs[]; 
    dis[s] = drs[s] = 0;				//设置初始点; 
    for(int k=1;k<n;k++)				//先遍历n次; 
    {
        check=0;
        if (b1)							//如果dis[]更新完了,设b1为0,就不用再遍历每条边去更新dis[]了,下面同理; 
        for(int i=1;i<=m;i++)
        {
            if(dis[v[i]]>dis[u[i]]+w[i])
            {
                dis[v[i]]=dis[u[i]]+w[i];
                check=1;
            }  
        }
        if (check==0) b1=0;
        check = 0;						//记得重新设定check的值; 
        if (b2)
        for(int i=1;i<=m;i++)			//求drs[]的过程相当于反向求初始点到各点的过程; 
        {
            if(drs[u[i]]>drs[v[i]]+w[i])
			{
				drs[u[i]]=drs[v[i]]+w[i];
				check = 1;
			}  
        }
        if (check==0) b2=0;
    }
//  for(int i=1; i<=n; i++)
//  {
//    	cout << dis[i] << " " << drs[i] << endl;
//	}
    for(int i=2;i<=n;i++)
        sum += dis[i]+drs[i];			//dis[]和drs[]求和; 
    cout << sum << endl;
    return 0;
}

蒟蒻一只,欢迎指正

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值