题解 | #小红修道路#

小红修道路

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索引的转换
全部评论

相关推荐

03-29 19:11
门头沟学院 Java
wyp_davis:是可以这样的,不过只要交钱就是假的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务