Skip to content

Commit 2c728f5

Browse files
committed
atcoder A75 締切付き作業スケジューリング問題(Deadline Scheduling)
1 parent 60a2bff commit 2c728f5

8 files changed

Lines changed: 600 additions & 0 deletions

File tree

DataStructures/Trees/Heap/Deadline

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import sys
2+
from typing import List, Tuple
3+
4+
def main() -> None:
5+
input_data = sys.stdin.read().strip().splitlines()
6+
n: int = int(input_data[0])
7+
problems: List[Tuple[int, int]] = []
8+
9+
for line in input_data[1:]:
10+
parts = line.split()
11+
if len(parts) == 2:
12+
problems.append((int(parts[0]), int(parts[1])))
13+
else:
14+
raise ValueError("Each line must contain exactly two integers")
15+
16+
print(solve(n, problems))
17+
18+
if __name__ == "__main__":
19+
main()
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"container/heap"
6+
"fmt"
7+
"os"
8+
"sort"
9+
"strconv"
10+
"strings"
11+
)
12+
13+
// 問題の構造体
14+
type Problem struct {
15+
T int // 所要時間
16+
D int // 締切
17+
}
18+
19+
// 最大ヒープの実装
20+
type MaxHeap []int
21+
22+
func (h MaxHeap) Len() int { return len(h) }
23+
func (h MaxHeap) Less(i, j int) bool { return h[i] > h[j] } // 逆順で最大ヒープに
24+
func (h MaxHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
25+
func (h *MaxHeap) Push(x interface{}) { *h = append(*h, x.(int)) }
26+
func (h *MaxHeap) Pop() interface{} {
27+
old := *h
28+
n := len(old)
29+
x := old[n-1]
30+
*h = old[0 : n-1]
31+
return x
32+
}
33+
34+
func solve(N int, problems []Problem) int {
35+
// 締切 D で昇順ソート
36+
sort.Slice(problems, func(i, j int) bool {
37+
return problems[i].D < problems[j].D
38+
})
39+
40+
totalTime := 0
41+
h := &MaxHeap{}
42+
heap.Init(h)
43+
44+
for _, p := range problems {
45+
totalTime += p.T
46+
heap.Push(h, p.T)
47+
48+
if totalTime > p.D {
49+
removed := heap.Pop(h).(int)
50+
totalTime -= removed
51+
}
52+
}
53+
54+
return h.Len()
55+
}
56+
57+
func main() {
58+
scanner := bufio.NewScanner(os.Stdin)
59+
scanner.Scan()
60+
N, _ := strconv.Atoi(scanner.Text())
61+
62+
var problems []Problem
63+
for i := 0; i < N; i++ {
64+
scanner.Scan()
65+
parts := strings.Fields(scanner.Text())
66+
T, _ := strconv.Atoi(parts[0])
67+
D, _ := strconv.Atoi(parts[1])
68+
problems = append(problems, Problem{T, D})
69+
}
70+
71+
result := solve(N, problems)
72+
fmt.Println(result)
73+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* 問題データの型:int T(所要時間), int D(締切)
7+
*/
8+
class Problem {
9+
public int $T;
10+
public int $D;
11+
12+
public function __construct(int $T, int $D) {
13+
$this->T = $T;
14+
$this->D = $D;
15+
}
16+
}
17+
18+
/**
19+
* メインの問題解決ロジック
20+
*
21+
* @param int $N
22+
* @param array<Problem> $problems
23+
* @return int
24+
*/
25+
function solve(int $N, array $problems): int {
26+
// 締切Dの昇順でソート
27+
usort($problems, function (Problem $a, Problem $b): int {
28+
return $a->D <=> $b->D;
29+
});
30+
31+
/** @var SplPriorityQueue<int> $heap 最大ヒープとして使用 */
32+
$heap = new SplPriorityQueue();
33+
$totalTime = 0;
34+
35+
foreach ($problems as $p) {
36+
$totalTime += $p->T;
37+
$heap->insert($p->T, $p->T); // priority = T なので最大ヒープ動作
38+
39+
if ($totalTime > $p->D) {
40+
$removed = $heap->extract();
41+
$totalTime -= $removed;
42+
}
43+
}
44+
45+
return $heap->count();
46+
}
47+
48+
/**
49+
* 標準入力からの処理
50+
*/
51+
function main(): void {
52+
$lines = explode("\n", trim(file_get_contents("php://stdin")));
53+
$N = intval(array_shift($lines));
54+
$problems = [];
55+
56+
foreach ($lines as $line) {
57+
[$T, $D] = array_map('intval', explode(" ", $line));
58+
$problems[] = new Problem($T, $D);
59+
}
60+
61+
echo solve($N, $problems) . PHP_EOL;
62+
}
63+
64+
main();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import sys
2+
import heapq
3+
from typing import List, Tuple
4+
5+
def solve(n: int, problems: List[Tuple[int, int]]) -> int:
6+
# 締切Dで昇順ソート
7+
problems.sort(key=lambda x: x[1])
8+
9+
total_time: int = 0
10+
max_heap: List[int] = [] # Pythonはmin-heapなので、-Tを使って最大ヒープにする
11+
12+
for t, d in problems:
13+
total_time += t
14+
heapq.heappush(max_heap, -t) # 最大ヒープとして扱うため -t
15+
16+
if total_time > d:
17+
removed: int = -heapq.heappop(max_heap) # 最大値(時間のかかる問題)を除く
18+
total_time -= removed
19+
20+
return len(max_heap)
21+
22+
def main() -> None:
23+
input_data = sys.stdin.read().strip().splitlines()
24+
n: int = int(input_data[0])
25+
problems: List[Tuple[int, int]] = []
26+
27+
for line in input_data[1:]:
28+
parts = line.split()
29+
if len(parts) == 2:
30+
problems.append((int(parts[0]), int(parts[1])))
31+
else:
32+
raise ValueError("Each line must contain exactly two integers")
33+
34+
print(solve(n, problems))
35+
36+
if __name__ == "__main__":
37+
main()
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import * as fs from 'fs';
2+
3+
// 最大ヒープ(Max Heap)クラスの定義
4+
class MaxHeap {
5+
private data: number[] = [];
6+
7+
push(val: number): void {
8+
this.data.push(val);
9+
this.bubbleUp(this.data.length - 1);
10+
}
11+
12+
pop(): number | null {
13+
if (this.data.length === 0) return null;
14+
const max = this.data[0];
15+
const last = this.data.pop()!;
16+
if (this.data.length > 0) {
17+
this.data[0] = last;
18+
this.bubbleDown(0);
19+
}
20+
return max;
21+
}
22+
23+
size(): number {
24+
return this.data.length;
25+
}
26+
27+
private bubbleUp(index: number): void {
28+
while (index > 0) {
29+
const parent = Math.floor((index - 1) / 2);
30+
if (this.data[parent] >= this.data[index]) break;
31+
[this.data[parent], this.data[index]] = [this.data[index], this.data[parent]];
32+
index = parent;
33+
}
34+
}
35+
36+
private bubbleDown(index: number): void {
37+
const length = this.data.length;
38+
while (true) {
39+
let left = 2 * index + 1;
40+
let right = 2 * index + 2;
41+
let largest = index;
42+
43+
if (left < length && this.data[left] > this.data[largest]) {
44+
largest = left;
45+
}
46+
if (right < length && this.data[right] > this.data[largest]) {
47+
largest = right;
48+
}
49+
if (largest === index) break;
50+
51+
[this.data[largest], this.data[index]] = [this.data[index], this.data[largest]];
52+
index = largest;
53+
}
54+
}
55+
}
56+
57+
// メイン処理関数
58+
function main(input: string): void {
59+
const lines = input.trim().split('\n');
60+
const N = parseInt(lines[0]);
61+
const problems: { T: number; D: number }[] = [];
62+
63+
for (let i = 1; i <= N; i++) {
64+
const [T, D] = lines[i].split(' ').map(Number);
65+
problems.push({ T, D });
66+
}
67+
68+
// 締切D順にソート
69+
problems.sort((a, b) => a.D - b.D);
70+
71+
const heap = new MaxHeap();
72+
let totalTime = 0;
73+
74+
for (const { T, D } of problems) {
75+
totalTime += T;
76+
heap.push(T);
77+
78+
if (totalTime > D) {
79+
const removed = heap.pop()!;
80+
totalTime -= removed;
81+
}
82+
}
83+
84+
console.log(heap.size());
85+
}
86+
87+
// 標準入力の読み込み
88+
main(fs.readFileSync(0, 'utf8'));
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const fs = require("fs");
2+
3+
function main(input) {
4+
const lines = input.trim().split("\n");
5+
const N = parseInt(lines[0]);
6+
const problems = lines.slice(1).map(line => {
7+
const [T, D] = line.split(" ").map(Number);
8+
return { T, D };
9+
});
10+
11+
// 締切順にソート
12+
problems.sort((a, b) => a.D - b.D);
13+
14+
// 優先度付きキュー(最大ヒープ)として時間を格納する
15+
const timeHeap = [];
16+
let currentTime = 0;
17+
18+
for (const { T, D } of problems) {
19+
currentTime += T;
20+
timeHeap.push(T);
21+
// 最大ヒープを保つため降順にソート
22+
timeHeap.sort((a, b) => b - a);
23+
24+
// 締切を超えたら、最も時間のかかる問題を削除
25+
if (currentTime > D) {
26+
const longest = timeHeap.shift(); // 最大値を削除
27+
currentTime -= longest;
28+
}
29+
}
30+
31+
console.log(timeHeap.length);
32+
}
33+
34+
// 標準入力から
35+
main(fs.readFileSync(0, "utf8"));

0 commit comments

Comments
 (0)