Skip to content

Commit 946752f

Browse files
authored
Merge pull request #57 from myoshi2891/dev/macbook_pro
atcoder A73 - Marathon Route Dijkstra 法(最短経路探索)
2 parents 3142f3d + e99b77f commit 946752f

6 files changed

Lines changed: 593 additions & 0 deletions

File tree

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"container/heap"
6+
"fmt"
7+
"os"
8+
)
9+
10+
type Edge struct {
11+
to int
12+
cost int
13+
tree int
14+
}
15+
16+
type Item struct {
17+
cost int
18+
ntree int // -tree(木の多い方を優先するために負にする)
19+
node int
20+
}
21+
type PriorityQueue []*Item
22+
23+
func (pq PriorityQueue) Len() int { return len(pq) }
24+
func (pq PriorityQueue) Less(i, j int) bool {
25+
if pq[i].cost != pq[j].cost {
26+
return pq[i].cost < pq[j].cost
27+
}
28+
return pq[i].ntree < pq[j].ntree // 木の本数が多い(ntreeが小さい)方が優先
29+
}
30+
func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] }
31+
func (pq *PriorityQueue) Push(x any) { *pq = append(*pq, x.(*Item)) }
32+
func (pq *PriorityQueue) Pop() any {
33+
old := *pq
34+
n := len(old)
35+
item := old[n-1]
36+
*pq = old[0 : n-1]
37+
return item
38+
}
39+
40+
func main() {
41+
sc := bufio.NewScanner(os.Stdin)
42+
sc.Split(bufio.ScanWords)
43+
readInt := func() int {
44+
sc.Scan()
45+
n := 0
46+
for _, b := range sc.Bytes() {
47+
n = n*10 + int(b-'0')
48+
}
49+
return n
50+
}
51+
52+
N := readInt()
53+
M := readInt()
54+
graph := make([][]Edge, N+1)
55+
56+
for i := 0; i < M; i++ {
57+
a := readInt()
58+
b := readInt()
59+
c := readInt()
60+
d := readInt()
61+
graph[a] = append(graph[a], Edge{to: b, cost: c, tree: d})
62+
graph[b] = append(graph[b], Edge{to: a, cost: c, tree: d})
63+
}
64+
65+
const INF = int(1e9)
66+
dist := make([]int, N+1)
67+
trees := make([]int, N+1)
68+
for i := 1; i <= N; i++ {
69+
dist[i] = INF
70+
trees[i] = -1
71+
}
72+
dist[1] = 0
73+
trees[1] = 0
74+
75+
pq := &PriorityQueue{}
76+
heap.Push(pq, &Item{cost: 0, ntree: 0, node: 1})
77+
78+
for pq.Len() > 0 {
79+
item := heap.Pop(pq).(*Item)
80+
cost, negTrees, u := item.cost, item.ntree, item.node
81+
curTrees := -negTrees
82+
83+
if cost > dist[u] || (cost == dist[u] && curTrees < trees[u]) {
84+
continue
85+
}
86+
87+
for _, e := range graph[u] {
88+
newCost := cost + e.cost
89+
newTrees := curTrees + e.tree
90+
if newCost < dist[e.to] || (newCost == dist[e.to] && newTrees > trees[e.to]) {
91+
dist[e.to] = newCost
92+
trees[e.to] = newTrees
93+
heap.Push(pq, &Item{cost: newCost, ntree: -newTrees, node: e.to})
94+
}
95+
}
96+
}
97+
98+
fmt.Println(dist[N], trees[N])
99+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
const fs = require("fs");
2+
3+
const input = fs.readFileSync(0, "utf8").trim().split("\n");
4+
const [N, M] = input[0].split(" ").map(Number);
5+
6+
const graph = Array.from({ length: N + 1 }, () => []);
7+
for (let i = 1; i <= M; i++) {
8+
const [a, b, c, d] = input[i].split(" ").map(Number);
9+
graph[a].push({ to: b, cost: c, tree: d });
10+
graph[b].push({ to: a, cost: c, tree: d });
11+
}
12+
13+
// ==============================
14+
// 自前の最小ヒープ (Priority Queue)
15+
// ==============================
16+
class MinHeap {
17+
constructor() {
18+
this.heap = [];
19+
}
20+
21+
push(item) {
22+
this.heap.push(item);
23+
this._siftUp();
24+
}
25+
26+
pop() {
27+
if (this.heap.length === 0) return null;
28+
const top = this.heap[0];
29+
const end = this.heap.pop();
30+
if (this.heap.length !== 0) {
31+
this.heap[0] = end;
32+
this._siftDown();
33+
}
34+
return top;
35+
}
36+
37+
isEmpty() {
38+
return this.heap.length === 0;
39+
}
40+
41+
_siftUp() {
42+
let i = this.heap.length - 1;
43+
while (i > 0) {
44+
const p = Math.floor((i - 1) / 2);
45+
if (this._compare(this.heap[i], this.heap[p]) < 0) {
46+
[this.heap[i], this.heap[p]] = [this.heap[p], this.heap[i]];
47+
i = p;
48+
} else break;
49+
}
50+
}
51+
52+
_siftDown() {
53+
let i = 0;
54+
const n = this.heap.length;
55+
while (true) {
56+
let smallest = i;
57+
const l = 2 * i + 1, r = 2 * i + 2;
58+
if (l < n && this._compare(this.heap[l], this.heap[smallest]) < 0) smallest = l;
59+
if (r < n && this._compare(this.heap[r], this.heap[smallest]) < 0) smallest = r;
60+
if (smallest === i) break;
61+
[this.heap[i], this.heap[smallest]] = [this.heap[smallest], this.heap[i]];
62+
i = smallest;
63+
}
64+
}
65+
66+
// 辞書順比較: [距離, -木の本数]
67+
_compare(a, b) {
68+
if (a[0] !== b[0]) return a[0] - b[0];
69+
return a[1] - b[1]; // -木の数が小さい = 木の数が多い
70+
}
71+
}
72+
73+
// ==============================
74+
// Dijkstra with 木の本数管理
75+
// ==============================
76+
77+
const dist = Array(N + 1).fill(Infinity);
78+
const treeCount = Array(N + 1).fill(-Infinity);
79+
dist[1] = 0;
80+
treeCount[1] = 0;
81+
82+
const pq = new MinHeap();
83+
pq.push([0, 0, 1]); // [距離, -木の数, 頂点]
84+
85+
while (!pq.isEmpty()) {
86+
const [curCost, negTrees, u] = pq.pop();
87+
88+
if (curCost > dist[u]) continue;
89+
if (curCost === dist[u] && -negTrees < treeCount[u]) continue;
90+
91+
for (const { to: v, cost: c, tree: t } of graph[u]) {
92+
const newCost = curCost + c;
93+
const newTrees = -negTrees + t;
94+
if (
95+
newCost < dist[v] ||
96+
(newCost === dist[v] && newTrees > treeCount[v])
97+
) {
98+
dist[v] = newCost;
99+
treeCount[v] = newTrees;
100+
pq.push([newCost, -newTrees, v]);
101+
}
102+
}
103+
}
104+
105+
console.log(`${dist[N]} ${treeCount[N]}`);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
fscanf(STDIN, "%d %d", $N, $M);
4+
5+
// グラフ構築
6+
$graph = array_fill(0, $N + 1, []);
7+
for ($i = 0; $i < $M; $i++) {
8+
fscanf(STDIN, "%d %d %d %d", $a, $b, $c, $d);
9+
$graph[$a][] = [$b, $c, $d]; // [to, cost, tree]
10+
$graph[$b][] = [$a, $c, $d];
11+
}
12+
13+
// 最短距離・木の数
14+
$dist = array_fill(0, $N + 1, INF);
15+
$trees = array_fill(0, $N + 1, -INF);
16+
$dist[1] = 0;
17+
$trees[1] = 0;
18+
19+
// 優先度付きキュー(SplPriorityQueue 使用)
20+
class PQ extends SplPriorityQueue
21+
{
22+
public function compare($a, $b): int
23+
{
24+
// 辞書順:(距離が小) → (木が多)
25+
if ($a[0] === $b[0]) {
26+
return $b[1] <=> $a[1]; // 木の数多い方が優先
27+
}
28+
return $b[0] <=> $a[0]; // 距離小さい方が優先
29+
}
30+
}
31+
32+
$pq = new PQ();
33+
$pq->insert([0, 0, 1], [0, 0]); // [距離, -木の数, ノード], 優先度
34+
35+
while (!$pq->isEmpty()) {
36+
[$cost, $negTree, $u] = $pq->extract();
37+
$tree = -$negTree;
38+
39+
if ($cost > $dist[$u]) continue;
40+
if ($cost === $dist[$u] && $tree < $trees[$u]) continue;
41+
42+
foreach ($graph[$u] as [$v, $c, $t]) {
43+
$newCost = $cost + $c;
44+
$newTree = $tree + $t;
45+
46+
if (
47+
$newCost < $dist[$v] ||
48+
($newCost === $dist[$v] && $newTree > $trees[$v])
49+
) {
50+
$dist[$v] = $newCost;
51+
$trees[$v] = $newTree;
52+
$pq->insert([$newCost, -$newTree, $v], [$newCost, -$newTree]);
53+
}
54+
}
55+
}
56+
57+
echo $dist[$N] . " " . $trees[$N] . "\n";
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import sys
2+
import heapq
3+
from typing import List, Tuple
4+
5+
input = sys.stdin.readline
6+
7+
# 入力
8+
N, M = map(int, input().split())
9+
graph: List[List[Tuple[int, int, int]]] = [[] for _ in range(N + 1)]
10+
11+
for _ in range(M):
12+
a, b, c, d = map(int, input().split())
13+
graph[a].append((b, c, d)) # (to, cost, tree)
14+
graph[b].append((a, c, d)) # 双方向
15+
16+
# 初期化
17+
dist = [float('inf')] * (N + 1)
18+
trees = [-float('inf')] * (N + 1)
19+
dist[1] = 0
20+
trees[1] = 0
21+
22+
# ヒープ(優先度付きキュー) [cost, -treeCount, node]
23+
heap: List[Tuple[int, int, int]] = []
24+
heapq.heappush(heap, (0, 0, 1)) # (距離, -木の本数, ノード)
25+
26+
while heap:
27+
cost, neg_tree, u = heapq.heappop(heap)
28+
tree = -neg_tree
29+
30+
if cost > dist[u]:
31+
continue
32+
if cost == dist[u] and tree < trees[u]:
33+
continue
34+
35+
for v, c, t in graph[u]:
36+
new_cost = cost + c
37+
new_tree = tree + t
38+
if (new_cost < dist[v]) or (new_cost == dist[v] and new_tree > trees[v]):
39+
dist[v] = new_cost
40+
trees[v] = new_tree
41+
heapq.heappush(heap, (new_cost, -new_tree, v))
42+
43+
# 出力
44+
print(dist[N], trees[N])

0 commit comments

Comments
 (0)