luogu 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
输入保证任意两点都能互相到达。

思路:咋一看,还以为要用Floyd,但是n告诉你,Floyd肯定超时,所以我们选择使用dijkstra堆优化算法,分析一下,快递员从第二个结点到n个结点,只需要dijkstra一次,然后把所有的dist加起来即可,但是从2~n个结点回来,可不是一对多,是多对一,按照常规的思路,我们需要dji n-1次,然后把所有的dist[1]加起来,我试了一下,会超时,因此我们可以换个思路,建一个反向图如下图所示(2n个结点到结点1的距离等于反图中结点1到结点2n的距离)。这么一来我们只需要dji俩次即可,大大降低了时间复杂度。

在这里插入图片描述

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;

const int maxn = 2e3 + 100;
const int MAX = 1e8;
struct node{
    int to;
    int next;
    int weight;
}edge[100 * maxn];
int head[maxn];
int dist[maxn];
int cnt = 0;
bool vis[maxn];
int n, m;//n个点,m条边


void init()
{
    for(int i = 1; i <= n << 1; i++){//n个点
        dist[i] = MAX;
        vis[i] = false;
    }
}

void add(int u, int v, int cost)
{
    edge[cnt].weight = cost;
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

struct base{
    int point;
    int dist;
    bool operator < (const base&others)const{
        return dist > others.dist;
    }
};

void dijkstra(int s)
{
    priority_queue<base>q;
    dist[s] = 0;
    q.push((base){s, 0});
    while(!q.empty()){
        base current = q.top();
        q.pop();
        int u = current.point;
        int d = current.dist;
        if(vis[u])
            continue;
        else
            vis[u] = true;
        for(int i = head[u]; ~i; i = edge[i].next){
            int v = edge[i].to;
            int w = edge[i].weight;
            if(!vis[v] && dist[u] + w < dist[v]){
                dist[v] = dist[u] + w;
                q.push((base){v, dist[v]});
            }
        }
    }
}


int main()
{
    scanf("%d%d", &n, &m);
    init();
    fill(head + 1, head + 1 + n, -1);
    while(m--){
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);
        add(n + v, n + u, w);//[1+n, 2n]存放反向图
    }
    dijkstra(1);
    int sum = 0;
    for(int i = 2; i <= n; i++){
        sum += dist[i];
    }
    init();
    dijkstra(1 + n);
    for(int i = 1 + n; i <= n << 1; i++){
        sum += dist[i];
    }
    printf("%d\n", sum);
    return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值