E - 巡回配達 / Traveling Delivery 解説 by admin
Gemini 3.1 Pro (Thinking)Overview
This problem asks us to find the minimum cost of starting from a specified starting point \(S\), visiting all \(K\) specific delivery destinations, and then returning to the starting point \(S\).
Analysis
- What matters along Takahashi’s travel route is how he moves between the starting point \(S\) and the \(K\) delivery destinations \(T_1, \dots, T_K\).
- First, if we know the shortest distances between all pairs of these \(K+1\) points, the problem reduces to a “Traveling Salesman Problem (TSP) over \(K+1\) cities.”
- If we try all possible orderings of visiting the destinations (exhaustive search over permutations), there are up to \(15! \approx 1.3 \times 10^{12}\) possibilities, which would result in TLE (Time Limit Exceeded).
- However, noticing that the number of destinations \(K\) is at most \(15\), which is very small, we can use bit DP (dynamic programming) to dramatically speed up the exhaustive permutation search and solve the problem within a practical time limit.
Algorithm
This problem can be solved in two main steps: “precomputing shortest distances” and “searching for a tour using bit DP.”
Precomputing Shortest Distances (Dijkstra’s Algorithm) We define the \(K+1\) points consisting of the starting point \(S\) and the \(K\) delivery destinations \(T_1, \dots, T_K\) as “important points.” We run Dijkstra’s algorithm \(K+1\) times, once from each of these important points as the source. This allows us to construct a distance matrix containing the shortest distances between all pairs of important points.
Searching for a Tour (bit DP) We assign numbers \(0\) through \(K\) to the important points. The starting point \(S\) is numbered \(0\), and the destinations \(T_1, \dots, T_K\) are numbered \(1\) through \(K\) respectively. We define the following DP table:
- \(dp[\text{mask}][i]\): The minimum cost of a path where the set of destinations visited so far is \(\text{mask}\) (represented as bits in binary) and the current location is point \(i\).
Initialization: \(dp[0][0] = 0\) (no destinations have been visited yet and we are at point \(S\)); all other values are set to infinity (\(\infty\)).
Transition: From the current state \(dp[\text{mask}][i]\), we consider moving to a destination \(j\) that has not yet been visited (the \((j-1)\)-th bit of \(\text{mask}\) is \(0\)). $\(dp[\text{mask} \cup \{j\}][j] = \min(dp[\text{mask} \cup \{j\}][j], dp[\text{mask}][i] + \text{dist}[i][j])\)\( Here, \)\text{dist}[i][j]\( is the shortest distance from point \)i\( to point \)j$ computed in Step 1.
- Computing the Answer
From the state where all destinations have been visited (all \(K\) bits of \(\text{mask}\) are \(1\)), we need to return to the starting point \(S\) (point \(0\)).
For each point \(i\), we compute the minimum value of \(dp[\text{all destinations visited}][i] + \text{dist}[i][0]\). This is the desired answer. If the minimum value remains infinity, it means it is impossible to visit all destinations and return, so we output
-1.
Complexity
- Time complexity: \(O(K M \log N + 2^K K^2)\)
- Running Dijkstra’s algorithm \(K+1\) times takes \(O(K M \log N)\).
- The number of states in the bit DP is \(2^K \times (K+1)\), and for each state we try \(K\) possible transitions, resulting in \(O(2^K K^2)\).
- Under the constraints \(K \le 15, N \le 300, M \le 90000\), this runs sufficiently fast.
- Space complexity: \(O(N + M + 2^K K)\)
- The graph storage requires \(O(N + M)\), the distance matrix requires \(O(K^2)\), and the DP table requires \(O(2^K K)\) memory.
Implementation Notes
Using bit operations: The set of visited destinations \(\text{mask}\) is managed as an integer. Whether “the \(j\)-th destination has been visited” is checked with
mask & (1 << (j - 1)), and when visiting a new destination, the state is updated withmask | (1 << (j - 1)).Index management: By assigning index \(0\) to the starting point \(S\) and indices \(1\) through \(K\) to the destinations, state management in the DP and references to the distance matrix become straightforward.
Handling disconnected graphs: If there is no road and a point is unreachable, the distance is treated as infinity (
float('inf')). Make sure not to forget to exclude infinity values during DP transitions and when computing the final answer.Source Code
import sys
import heapq
def solve():
input_data = sys.stdin.read().split()
if not input_data:
return
N = int(input_data[0])
M = int(input_data[1])
adj = [[] for _ in range(N + 1)]
idx = 2
for _ in range(M):
u = int(input_data[idx])
v = int(input_data[idx+1])
w = int(input_data[idx+2])
adj[u].append((v, w))
idx += 3
S = int(input_data[idx])
K = int(input_data[idx+1])
idx += 2
T = []
for _ in range(K):
T.append(int(input_data[idx]))
idx += 1
targets = [S] + T
K_total = K + 1
dist_matrix = [[float('inf')] * K_total for _ in range(K_total)]
for i in range(K_total):
start_node = targets[i]
dist = [float('inf')] * (N + 1)
dist[start_node] = 0
pq = [(0, start_node)]
while pq:
d, u = heapq.heappop(pq)
if d > dist[u]:
continue
for v, w in adj[u]:
if dist[v] > d + w:
dist[v] = d + w
heapq.heappush(pq, (dist[v], v))
for j in range(K_total):
dist_matrix[i][j] = dist[targets[j]]
INF = float('inf')
dp = [[INF] * K_total for _ in range(1 << K)]
dp[0][0] = 0
for mask in range(1 << K):
dp_mask = dp[mask]
for i in range(K_total):
curr_cost = dp_mask[i]
if curr_cost == INF:
continue
dist_i = dist_matrix[i]
for j in range(1, K_total):
if not (mask & (1 << (j - 1))):
nxt_mask = mask | (1 << (j - 1))
cost = curr_cost + dist_i[j]
if dp[nxt_mask][j] > cost:
dp[nxt_mask][j] = cost
ans = INF
full_mask = (1 << K) - 1
for i in range(K_total):
if dp[full_mask][i] != INF and dist_matrix[i][0] != INF:
if ans > dp[full_mask][i] + dist_matrix[i][0]:
ans = dp[full_mask][i] + dist_matrix[i][0]
if ans == INF:
print(-1)
else:
print(ans)
if __name__ == '__main__':
solve()
This editorial was generated by gemini-3.1-pro-thinking.
投稿日時:
最終更新: