Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions Algorithm/DynamicProgramming/atCoder/B16/B16.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// 以下は、**Go 1.20.6** を用いた「カエルの最小ジャンプコスト」問題の解法です。
// **実行時間とメモリの消費量を最小限に抑える**ため、\*\*動的計画法(DP)+ 空間最適化(O(1) メモリ)\*\*を使用します。

// ## ✅ Go 実装(型明示・最小メモリ・高速)

package main

import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)

func min(a, b int) int {
if a < b {
return a
}
return b
}

func main() {
reader := bufio.NewReader(os.Stdin)

// 1行目:N
line1, _ := reader.ReadString('\n')
N, _ := strconv.Atoi(strings.TrimSpace(line1))

// 2行目:h[0]~h[N-1]
line2, _ := reader.ReadString('\n')
hStr := strings.Fields(line2)
h := make([]int, N)
for i := 0; i < N; i++ {
h[i], _ = strconv.Atoi(hStr[i])
}

if N == 2 {
fmt.Println(abs(h[1] - h[0]))
return
}

var prev2 int = 0 // dp[i-2]
var prev1 int = abs(h[1] - h[0]) // dp[i-1]

for i := 2; i < N; i++ {
cost1 := prev1 + abs(h[i]-h[i-1])
cost2 := prev2 + abs(h[i]-h[i-2])
curr := min(cost1, cost2)
prev2 = prev1
prev1 = curr
}

fmt.Println(prev1)
}

func abs(a int) int {
if a < 0 {
return -a
}
return a
}

// ## ✅ 入出力例

// 入力(標準入力):

// ```
// 6
// 30 10 60 10 60 50
// ```

// 出力:

// ```
// 40
// ```

// ---

// ## ✅ 計算量・メモリ量

// | 指標 | 値 |
// | ----- | --------------- |
// | 時間計算量 | `O(N)` |
// | 空間計算量 | `O(1)`(定数メモリのみ) |
// | 入力制約 | `2 ≤ N ≤ 10^5` |

// ---

// ## ✅ ポイントまとめ

// * **配列 `dp[]` を使わず**に、`prev1`, `prev2` の2つだけで更新する。
// * `abs()` でジャンプコストを計算。
// * `min()` 関数で2通りのジャンプを比較。

// ---

// ## ✅ フルDP版(O(N)メモリ)も参考に:

// ```go
// dp := make([]int, N)
// dp[0] = 0
// dp[1] = abs(h[1] - h[0])
// for i := 2; i < N; i++ {
// dp[i] = min(
// dp[i-1]+abs(h[i]-h[i-1]),
// dp[i-2]+abs(h[i]-h[i-2]),
// )
// }
// fmt.Println(dp[N-1])
// ```

94 changes: 94 additions & 0 deletions Algorithm/DynamicProgramming/atCoder/B16/B16.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// 以下に、指定された条件(Node.js 18.16.1、`fs` モジュール使用、実行時間・メモリ効率重視)に従って、**カエルの最小コストジャンプ問題**をJavaScriptで解いた実装を示します。

// ---

// ## ✅ アルゴリズム概要(動的計画法DP)

// * `dp[i]`: 足場 `i` に到達するための最小コスト。
// * 遷移式:

// * `dp[i] = min(dp[i-1] + abs(h[i] - h[i-1]), dp[i-2] + abs(h[i] - h[i-2]))`
// * 初期値:

// * `dp[0] = 0`
// * `dp[1] = abs(h[1] - h[0])`

// ---

// ## ✅ JavaScript (Node.js) 実装(`fs` 使用)

// ```javascript
// const fs = require('fs');

// function main(input) {
// const lines = input.trim().split('\n');
// const N = parseInt(lines[0], 10);
// const h = lines[1].split(' ').map(Number);

// const dp = new Array(N).fill(0);
// dp[0] = 0;
// dp[1] = Math.abs(h[1] - h[0]);

// for (let i = 2; i < N; i++) {
// dp[i] = Math.min(
// dp[i - 1] + Math.abs(h[i] - h[i - 1]),
// dp[i - 2] + Math.abs(h[i] - h[i - 2])
// );
// }

// console.log(dp[N - 1]);
// }

// // 標準入力から読み込む
// main(fs.readFileSync('/dev/stdin', 'utf8'));
// ```

// ---

// ## ✅ 計算量・メモリ使用量

// * **時間計算量**: `O(N)`(1回ずつループ)
// * **空間計算量**: `O(N)`(DP配列1本)

// * さらに最適化すれば `O(1)` でも可能(直近2要素のみ使用)

// ---

// ## ✅ 最適化バージョン(メモリ `O(1)`)

// ```javascript
const fs = require('fs');

function main(input) {
const lines = input.trim().split('\n');
const N = parseInt(lines[0], 10);
const h = lines[1].split(' ').map(Number);

let prev2 = 0; // dp[i-2]
let prev1 = Math.abs(h[1] - h[0]); // dp[i-1]

for (let i = 2; i < N; i++) {
const curr = Math.min(
prev1 + Math.abs(h[i] - h[i - 1]),
prev2 + Math.abs(h[i] - h[i - 2])
);
prev2 = prev1;
prev1 = curr;
}

console.log(prev1);
}

main(fs.readFileSync('/dev/stdin', 'utf8'));

// ## ✅ 入出力例テスト(例1)

// ```
// 入力:
// 4
// 10 30 40 20

// 出力:
// 30
// ```

100 changes: 100 additions & 0 deletions Algorithm/DynamicProgramming/atCoder/B16/B16.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<!-- 以下は、**PHP 8.2.8** での「カエルの最小ジャンプコスト」問題の実装です。
**処理時間・メモリの消費量を最小限に抑える**ため、\*\*動的計画法(DP)+ 空間最適化(O(1)メモリ)\*\*を採用しています。

---

## ✅ PHP 実装(型明示、O(1)メモリ最適化)
<?php

function main(): void {
$input = trim(stream_get_contents(STDIN));
$lines = explode("\n", $input);

/** @var int $N */
$N = (int)$lines[0];

/** @var array<int> $h */
$h = array_map('intval', explode(' ', trim($lines[1])));

if ($N === 2) {
echo abs($h[1] - $h[0]) . PHP_EOL;
return;
}

/** @var int $prev2 最小コスト(i-2) */
$prev2 = 0;

/** @var int $prev1 最小コスト(i-1) */
$prev1 = abs($h[1] - $h[0]);

for ($i = 2; $i < $N; ++$i) {
/** @var int $cost1 足場 i-1 から来た場合のコスト */
$cost1 = $prev1 + abs($h[$i] - $h[$i - 1]);

/** @var int $cost2 足場 i-2 から来た場合のコスト */
$cost2 = $prev2 + abs($h[$i] - $h[$i - 2]);

/** @var int $curr 現在の足場 i への最小コスト */
$curr = min($cost1, $cost2);

$prev2 = $prev1;
$prev1 = $curr;
}

echo $prev1 . PHP_EOL;
}

main();

// ## ✅ 入出力形式

// 標準入力から以下の形式で与えられます:

// ```
// N
// h1 h2 h3 ... hN
// ```

// ### 例:

// ```
// 6
// 30 10 60 10 60 50
// ```

// 出力:

// ```
// 40
// ```

// ---

// ## ✅ 計算量とメモリ効率

// | 指標 | 値 |
// | ----- | -------------- |
// | 時間計算量 | O(N) |
// | 空間計算量 | O(1)(定数個の変数のみ) |
// | 入力制約 | 2 ≤ N ≤ 10⁵ |

// ## ✅ 解法のポイント

// * `dp[i]` の代わりに、**直前2ステップ(`prev1`, `prev2`)だけ保持**。
// * `abs()` でジャンプコストを計算。
// * \*\*配列未使用(O(N))\*\*のバージョンも実装可能。

// ## ✅ O(N) メモリバージョン(DP配列使用)

// 参考用に、メモリを多く使うフルDP版も示します:

// ```php
// $dp = array_fill(0, $N, 0);
// $dp[1] = abs($h[1] - $h[0]);
// for ($i = 2; $i < $N; $i++) {
// $dp[$i] = min(
// $dp[$i - 1] + abs($h[$i] - $h[$i - 1]),
// $dp[$i - 2] + abs($h[$i] - $h[$i - 2])
// );
// }
// echo $dp[$N - 1] . PHP_EOL;
84 changes: 84 additions & 0 deletions Algorithm/DynamicProgramming/atCoder/B16/B16.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# 以下は、**Python (CPython 3.11.4)** を用いた「カエルの最小ジャンプコスト」問題の解法です。
# **処理時間・メモリ使用量を最適化**するため、**動的計画法(DP)+ メモリ O(1) に削減**した実装を提供します。

# ---

# ## ✅ Python 実装(型付き・高速・省メモリ)

# ```python
import sys

def main() -> None:
input: str = sys.stdin.read()
lines: list[str] = input.strip().split('\n')

N: int = int(lines[0])
h: list[int] = list(map(int, lines[1].split()))

if N == 2:
print(abs(h[1] - h[0]))
return

prev2: int = 0 # dp[0]
prev1: int = abs(h[1] - h[0]) # dp[1]

for i in range(2, N):
cost1: int = prev1 + abs(h[i] - h[i - 1])
cost2: int = prev2 + abs(h[i] - h[i - 2])
curr: int = min(cost1, cost2)
prev2, prev1 = prev1, curr

print(prev1)

if __name__ == "__main__":
main()

# ## ✅ 入出力形式

# 標準入力から以下のように与えられます:

# ```
# N
# h1 h2 h3 ... hN
# ```

# ---

# ## ✅ 実行例

# 入力:

# ```
# 6
# 30 10 60 10 60 50
# ```

# 出力:

# ```
# 40
# ```

# ---

# ## ✅ 計算量とメモリ使用量

# | 項目 | 内容 |
# | ----- | ------------------------------ |
# | 時間計算量 | `O(N)`(1ループ) |
# | 空間計算量 | `O(1)`(直前2個のみ) |
# | 入力制約 | `2 ≤ N ≤ 10^5`、`1 ≤ hᵢ ≤ 10^4` |

# ---

# ## ✅ 補足:DP配列を使ったフル版(メモリ O(N))

# 必要であれば以下のようにも書けます:

# ```python
# dp: list[int] = [0] * N
# dp[1] = abs(h[1] - h[0])
# for i in range(2, N):
# dp[i] = min(dp[i-1] + abs(h[i] - h[i-1]), dp[i-2] + abs(h[i] - h[i-2]))
# print(dp[N-1])
# ```
Loading