题解 | #小红修道路#

小红修道路

https://www.nowcoder.com/practice/b22011bdda6f43ddb9a34933ea5d737f

题目链接

小红修道路

题目描述

小红有一个 个点 条边的无向图,每条边有一个权值 。小红现在计划修 条双向道路,起点是 号点,终点是其他顶点。假设修了这 条路后,从 号点到其他点的距离为 ,小红想知道,可以少修多少条路,使得从 号点到其他点的距离仍然为

输入:

  • 第一行三个整数 ,表示点数、边数、以及小红计划修的路数
  • 接下来 行,每行三个整数 ,表示一条边的两个端点以及权值
  • 接下来 行,每行两个整数 ,表示计划修从 号点到 号点的一条路,长度为

输出:

  • 输出一个整数,表示可以少修的路数

解题思路

这是一个最短路径问题,可以通过以下步骤解决:

  1. 关键发现:

    • 如果原图中已经存在更短的路径,这条路可以不修
    • 如果到某个点有多条相同长度的最短路径,可以省略其中一条
    • 需要记录到每个点的最短路径条数
  2. 解题策略:

    • 使用改进的Dijkstra算法计算最短路径
    • 同时记录到每个点的最短路径条数
    • 根据最短路径长度和条数判断是否可以省略
  3. 具体步骤:

    • 将计划修的路也加入图中
    • 计算包含所有路的最短路径和路径条数
    • 如果原图路径更短或有多条等长路径,则可以省略

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

template <typename T>
auto dijkstra(const vector<vector<pair<int, int>>> &g,
              const vector<T> &w, int start) -> pair<vector<int64_t>, vector<int>> {
    vector<int64_t> dis(g.size(), -1);
    vector<int> cnt(g.size()); 
    cnt[start] = 1;

    priority_queue<tuple<int64_t, int, int>> q;
    q.emplace(0, start, -1);
    while (!q.empty()) {
        auto [d, u, f] = q.top();
        q.pop();

        if (f != -1 && (dis[u] == -1 || dis[u] == -d)) {
            cnt[u]++;
        }
        if (dis[u] != -1) continue;
        dis[u] = -d;

        for (auto [v, j] : g[u]) {
            q.emplace(d - w[j], v, u);
        }
    }
    return {dis, cnt};
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m, k;
    cin >> n >> m >> k;
    vector<vector<pair<int, int>>> g(n);
    vector<int> w(m + k);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v >> w[i];
        u--, v--;
        g[u].emplace_back(v, i);
        g[v].emplace_back(u, i);
    }

    vector<pair<int, int>> p;
    for (int i = m; i < m + k; i++) {
        int s;
        cin >> s >> w[i];
        s--;
        p.emplace_back(s, w[i]);
        g[0].emplace_back(s, i);
        g[s].emplace_back(0, i);
    }

    auto [dis, cnt] = dijkstra(g, w, 0);

    int ans = 0;
    for (auto [s, y] : p) {
        if (dis[s] < y) {
            ans++;
        } else if (cnt[s] >= 2) {
            ans++;
            cnt[s]--;
        }
    }

    cout << ans << "\n";

    return 0;
}
import java.util.*;

public class Main {
    static class Edge {
        int v, idx;
        Edge(int v, int idx) {
            this.v = v;
            this.idx = idx;
        }
    }
    
    static class State {
        long dist;
        int u, from;
        State(long dist, int u, int from) {
            this.dist = dist;
            this.u = u;
            this.from = from;
        }
    }
    
    static Pair<long[], int[]> dijkstra(List<List<Edge>> g, int[] w, int start) {
        int n = g.size();
        long[] dist = new long[n];
        Arrays.fill(dist, -1);
        int[] cnt = new int[n];
        cnt[start] = 1;
        
        PriorityQueue<State> pq = new PriorityQueue<>((a, b) -> Long.compare(a.dist, b.dist));
        pq.offer(new State(0, start, -1));
        
        while(!pq.isEmpty()) {
            State cur = pq.poll();
            
            if(cur.from != -1 && (dist[cur.u] == -1 || dist[cur.u] == cur.dist)) {
                cnt[cur.u]++;
            }
            if(dist[cur.u] != -1) continue;
            dist[cur.u] = cur.dist;
            
            for(Edge e : g.get(cur.u)) {
                pq.offer(new State(cur.dist + w[e.idx], e.v, cur.u));
            }
        }
        
        return new Pair<>(dist, cnt);
    }
    
    static class Pair<T, U> {
        T first;
        U second;
        Pair(T first, U second) {
            this.first = first;
            this.second = second;
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int k = sc.nextInt();
        
        List<List<Edge>> g = new ArrayList<>();
        for(int i = 0; i < n; i++) {
            g.add(new ArrayList<>());
        }
        
        int[] w = new int[m + k];
        for(int i = 0; i < m; i++) {
            int u = sc.nextInt() - 1;
            int v = sc.nextInt() - 1;
            w[i] = sc.nextInt();
            g.get(u).add(new Edge(v, i));
            g.get(v).add(new Edge(u, i));
        }
        
        List<Pair<Integer, Integer>> p = new ArrayList<>();
        for(int i = m; i < m + k; i++) {
            int s = sc.nextInt() - 1;
            w[i] = sc.nextInt();
            p.add(new Pair<>(s, w[i]));
            g.get(0).add(new Edge(s, i));
            g.get(s).add(new Edge(0, i));
        }
        
        Pair<long[], int[]> result = dijkstra(g, w, 0);
        long[] dist = result.first;
        int[] cnt = result.second;
        
        int ans = 0;
        for(Pair<Integer, Integer> edge : p) {
            if(dist[edge.first] < edge.second) {
                ans++;
            } else if(cnt[edge.first] >= 2) {
                ans++;
                cnt[edge.first]--;
            }
        }
        
        System.out.println(ans);
    }
}
from heapq import heappush, heappop
from typing import List, Tuple
import sys
input=sys.stdin.readline

def dijkstra(g: List[List[Tuple[int, int]]], w: List[int], start: int) -> Tuple[List[int], List[int]]:
    n = len(g)
    dis = [-1] * n
    cnt = [0] * n
    cnt[start] = 1
    
    q = []  # 使用负数实现最大堆
    heappush(q, (0, -start, 1))  # (distance, vertex, from)
    
    while q:
        d, u, f = heappop(q)
        d=-d
        u=-u
        f=-f
        if f != -1 and (dis[u] == -1 or dis[u] == -d):
            cnt[u] += 1
        if dis[u] != -1:
            continue
        dis[u] = -d
        
        for v, j in g[u]:
            heappush(q, (-d + w[j], -v, -u))
    
    return dis, cnt

n, m, k = map(int, input().split())
g = [[] for _ in range(n)]
w = [0] * (m + k)

# 读入原图的边
for i in range(m):
    u, v, weight = map(int, input().split())
    u -= 1
    v -= 1
    w[i] = weight
    g[u].append((v, i))
    g[v].append((u, i))

# 读入计划修的路
p = []
for i in range(m, m + k):
    s, length = map(int, input().split())
    s -= 1
    w[i] = length
    p.append((s, length))
    g[0].append((s, i))
    g[s].append((0, i))

dis, cnt = dijkstra(g, w, 0)

ans = 0
for s, y in p:
    if dis[s] < y:
        ans += 1
    elif cnt[s] >= 2:
        ans += 1
        cnt[s] -= 1

print(ans)

算法及复杂度

  • 算法:改进的Dijkstra最短路径算法
  • 时间复杂度: - Dijkstra算法的复杂度
  • 空间复杂度: - 需要存储图的邻接表和距离数组

注意:

  1. 需要记录到每个点的最短路径条数
  2. 当存在多条等长最短路径时可以省略其中一条
  3. 图是无向图,需要添加双向边
  4. 需要处理0-based和1-based索引的转换
全部评论

相关推荐

不愿透露姓名的神秘牛友
昨天 12:31
以前小时候我最痛恨出轨、偷情的人,无论男女,为什么会出轨?现在我成了自己最讨厌的人,没想到分享的东西在牛客会被这么多人看,大家的评价都很中肯,我也认同,想过一一回复,但我还是收声了,我想我应该说说这件事,这件事一直压在我心里,是个很大的心结,上面说了人为什么出轨,我大概能明白了。我们大一下半年开始恋爱,开始恋爱,我给出了我铭记3年的承诺,我对她好一辈子,我永远不会背叛,我责任心太重,我觉得跟了我,我就要照顾她一辈子,我们在一起3年我都没有碰过她,她说往东我就往东,她说什么我做什么,她要我干什么,我就干什么!在学校很美好,中途也出过一些小插曲,比如男闺蜜、男闺蜜2号等等等。但我都强迫她改掉了,我...
牛客刘北:两个缺爱的人是没有办法好好在一起的,但世界上哪有什么是非对错?你后悔你们在一起了,但是刚刚在一起的美好也是真的呀,因为其他人的出现,你开始想要了最开始的自己,你的确对不起自己,21岁的你望高物远,你完全可以不谈恋爱,去过你想要的生活,你向往自由,在一起之后,你要想的不是一个人,而是两个人,你不是变心了,就像你说的,你受够了,你不想包容了,冷静几天是你最优的选择,爱人先爱己。
社会教会你的第一课
点赞 评论 收藏
分享
Yki_:你要算时间成本呀,研究生两三年,博士三四年,加起来就五六年了,如果你本科去腾讯干五年,多领五年的年薪,加上公司内涨薪,可能到时候十五年总薪资也跟博士差不多
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务