Rustで動的計画法:Slimes
はじめに
動的計画法を実装してみて、Rustの勉強をやってみる。問題としてはEducational DP Contestという動的計画法の練習を目的としたコンテストのものを使用。
AからZまで問題が設定されているが、今回はNのSlimesを解いてみる。
利用したライブラリ
標準入力からデータを読み取る部分はproconio
を利用。
久々にchmin!
も使う。
完成したコード
dequeueの時と同じように、dp[i][j]
を
use proconio::input;
fn main(){
input!(
n: usize,
slimes: [u64; n]
);
let mut dp = Vec::with_capacity(n);
for i in 0..n {
dp.push(vec![0u64; i+1]);
}
let cost = |j: usize, i: usize| -> u64 { (&slimes[j..i+1]).iter().sum() };
for j in 1..n {
for i in j..n {
let j_x = i - j; // (dp[j].len() - 1) - i
dp[i][j_x] = dp[j_x][j_x] + dp[i][j_x + 1];
for k in 1..j {
chmin!(dp[i][j_x], dp[j_x + k][j_x] + dp[i][j_x + k + 1]);
}
dp[i][j_x] += cost(j_x, i);
}
}
println!("{}, {}, {}", n, start.elapsed().as_nanos(), dp[n - 1][0]);
}
アルゴリズム
dp[i][j]
を求めるには、d[i][k+1] + d[k][j]
のコストが最も小さい組み合わせを見つければ良い。
dp[i][j]
を計算するまでに、必要なコストを全て計算するためには、下三角行列の斜面、行列の対角線から順番に斜めに計算していけば良い。ループでは書きにくいのでj_x
を作って、これを
なお、dp[]
はゼロで初期化しているので最初の1つ (k=0
) だけはベタに計算して代入している。
イテレータの活用
cost
という関数 (closure) で求めるようにしている。ここの計算結果を保存しながら進めるのもいいのだが、
ここはfor
で実装するとすると以下のようになると思うが、iter()
を使った方がすっきり書ける。おそらく処理時間はそんなに変わらないと思うが。
let cost = |i: usize, j: usize| -> u64 {
let mut sum = 0;
for k in i..j+1 {
sum += slimes[k];
}
sum
}
計算時間の測定
関連記事
Rustで動的計画法の実装:
🐸Frog | 🌴Vacation | 🎒Knapsack | 🐍LCS | 🚶♂️Longest Path | 🕸️Grid | 💰Coins | 🍣Sushi | 🪨Stones | 📐dequeue | 🍬Candies | 🫥Slimes | 💑Matching | 🌲Indipendent Set | 🌻Flowers | 👣Walk | 🖥️Digit Sum | 🎰Permutation | 🐰Grouping | 🌿Subtree | ⏱️Intervals | 🗼Tower | 🐸Frog3
Discussion