公式

E - 除雪車の巡回 / Snow Plow Routing 解説 by admin 印刷ページ

DeepSeek V3

Overview

This problem asks us to find the shortest route that traverses every edge of a given connected graph at least once and returns to the starting point (the Chinese Postman Problem).

Analysis

For a closed walk that traverses every edge of a graph at least once (Eulerian circuit) to exist, every vertex must have even degree (the condition for an Eulerian circuit). However, the original graph may contain vertices with odd degree.

If there are vertices with odd degree, we need to make additional traversals between those vertices. In other words, we need to add to the total weight of the original graph’s edges the cost of optimally pairing up the odd-degree vertices and traversing between them.

Since the constraints state that “the number of odd-degree vertices is at most 16,” it is efficient to precompute the shortest distances between these vertices and use bit DP to find the optimal pairing.

Algorithm

  1. Graph Construction: Build the graph in adjacency list form from the input
  2. Extracting Odd-Degree Vertices: List all vertices with odd degree
  3. All-Pairs Shortest Distances: Compute the shortest distances between odd-degree vertices using BFS
  4. Minimum Weight Perfect Matching: Compute the minimum cost of pairing the odd-degree vertices using bit DP
  5. Computing the Result: Output the total edge weight sum + minimum matching cost

Specifically: - If there are 0 odd-degree vertices, simply output the total edge weight sum - If there are odd-degree vertices, find the minimum cost of optimally pairing them and add it to the total sum

Complexity

  • Time complexity: \(O(N + M + K^2 \cdot N + 2^K \cdot K^2)\)
    • \(K\): number of odd-degree vertices (at most 16)
    • Graph construction: \(O(N + M)\)
    • All-pairs shortest distances: \(O(K \cdot (N + M))\)
    • Bit DP: \(O(2^K \cdot K^2)\)
  • Space complexity: \(O(N + M + 2^K + K^2)\)

Implementation Notes

  • Since there can be multiple edges, register each edge in both directions in the adjacency list

  • BFS is sufficient for shortest distance computation (not Dijkstra) — although weights are positive, BFS works fine

  • In bit DP, manage states with bitmasks and pair unpaired vertices in order

  • Initialize with large values (\(10^{18}\)) to prevent overflow

    Source Code

import sys
from collections import deque

def main():
    data = sys.stdin.read().split()
    if not data:
        return
    
    n = int(data[0])
    m = int(data[1])
    edges = []
    graph = [[] for _ in range(n+1)]
    total = 0
    index = 2
    deg = [0] * (n+1)
    
    for i in range(m):
        u = int(data[index]); v = int(data[index+1]); w = int(data[index+2])
        index += 3
        edges.append((u, v, w))
        graph[u].append((v, w))
        graph[v].append((u, w))
        deg[u] += 1
        deg[v] += 1
        total += w
    
    odd_vertices = []
    for i in range(1, n+1):
        if deg[i] % 2 == 1:
            odd_vertices.append(i)
    
    k = len(odd_vertices)
    if k == 0:
        print(total)
        return
        
    dist = [[10**18] * k for _ in range(k)]
    
    for i in range(k):
        start = odd_vertices[i]
        d = [10**18] * (n+1)
        d[start] = 0
        q = deque([start])
        while q:
            u = q.popleft()
            for v, w in graph[u]:
                if d[v] > d[u] + w:
                    d[v] = d[u] + w
                    q.append(v)
        for j in range(k):
            dist[i][j] = d[odd_vertices[j]]
    
    dp = [10**18] * (1 << k)
    dp[0] = 0
    
    for mask in range(1 << k):
        if dp[mask] == 10**18:
            continue
        i = 0
        while i < k:
            if mask & (1 << i):
                i += 1
                continue
            j = i + 1
            while j < k:
                if mask & (1 << j):
                    j += 1
                    continue
                new_mask = mask | (1 << i) | (1 << j)
                cost = dp[mask] + dist[i][j]
                if dp[new_mask] > cost:
                    dp[new_mask] = cost
                j += 1
            i += 1
    
    print(total + dp[(1 << k) - 1])

if __name__ == "__main__":
    main()

This editorial was generated by deepseekv3.

投稿日時:
最終更新: