2023-06-18
やること宣言
gaaamii.icon
AtCoderのABC306の振り返りをする
勉強中メモ
gaaamii.icon
2023/6/17 21:00〜のABC306に参加した
https://atcoder.jp/users/gaaamii/history/share/abc306
ABCはできたけどDがわからずだった
D問題
https://atcoder.jp/contests/abc306/tasks/abc306_d
どのレベルでわからなかったというと、文意はわかったけど解法が全く出てこなかった。
美味しいものをなるべくたくさん食べたときの美味しさの総和を求める
毒入り(健康なときに食べると腹痛になる、腹痛のとき食べると死ぬ)と解毒剤入(腹痛のとき食べると回復する)の2種類で
美味しさは-200だったり0だったり100だったり。まずいものがあるので負の数もあり得るという感じ。
つまりまずいもの、毒入りは食べたくないけど、まずくても解毒剤はほしい、あるいは毒入りでも美味しいから食べたい、というケースがある。
なので、総和が大きくなるようにアルゴリズムを考えられたら正解が出せるぽい。けどわからなかった
解説を見てみる
https://www.youtube.com/watch?v=Xk2ypalibo8&list=PLLeJZg4opYKbBSz6tR14WsrD-RiRlJlwB
単純に考えると全探索だが、その場合2のN乗の計算量になる(Nは3*10の5乗)
なので、DP(Dynamic Programming、動的計画法)を使うとよいらしい
今回の場合、毒状態かどうかがわかれば、残りをどう食べるべきかがわかる
iをindex、pを毒状態かどうか(0か1)としたとき、2つの方法がある
f(i,p)というメモ化再帰関数
dp[i][p]のDPテーブルをつくる
解説動画わかりやすく説明してもらってるけどC++だからすこし理解がしにくい
vectorってどういうデータだ
std::vector(C++)
配列か。vector(N, 初期値)みたいに書けるっぽい
解説動画だと-INFで初期化している
Rubyで書いている方もいたのでこちらの方が読みやすい
https://atcoder.jp/contests/abc306/submissions/42369003
DPがいまいち理解できない
問題解決力を鍛える!アルゴリズムとデータ構造という本で、DPの説明を少し読んでみる
https://atcoder.jp/contests/dp/tasks/dp_a
この問題が例にあげられている
こっちのほうは一次元の配列なので理解しやすい
文章読んで理解できた気がするけど、念のため自分でもRubyで書いてみる
書いてみた
code:ruby
n = gets.chomp.to_i
$heights = gets.chomp.split(" ").map(&:to_i)
dp = 0
def get_cost(i, j)
($heightsi - $heightsj).abs
end
$heights.each_with_index do |h, i|
next if i.zero?
if i == 1
dpi = get_cost(0, 1)
next
end
no_skip_cost = dpi - 1 + get_cost(i, i - 1)
with_skip_cost = dpi - 2 + get_cost(i, i - 2)
dpi = no_skip_cost, with_skip_cost.min
end
puts dpn - 1
https://atcoder.jp/contests/dp/submissions/42565650
こういう構造(この例だと、Nまでの最短経路を達成するには、その途中でも最短経路を通ってきている必要がある)を部分構造最適性っていうのか
やったこと
gaaamii.icon
2023-06-18 日報