# 問題解決力を鍛える!アルゴリズムとデータ構造 ## 第6章 - 6.3〜を読む - 任意参加 - ファシリテーター: teruya ### 話す・書く順番決めルーレット in Ruby ```ruby ['hsu', 'chen', 'teruya', 'kanazawa', 'okura', 'tsujita'].shuffle.each { |v| puts ">[name=#{v}]\n\n" } ``` in JavaScript ```javascript const l = ['hsu', 'chen', 'teruya', 'kanazawa', 'okura', 'tsujita'] l[Math.floor(Math.random()*l.length)] ``` ### ファシリテーター決め方 - `%w(hsu chen teruya kanazawa okura kanno)`の順番でやっていく ### 参加者がやること - 事前に決められた章を読む - 学んだことやわからなかったことを書き込む(任意) 当日 - 最初に感想や質問を書く時間を設ける(10分) - 時間枠 60分 - 延長枠 30分 ### 勉強会時にやること 各自学びや気付き、疑問を発表していく ファシリテーターがよしなに議論を進める 終了前に勉強会を振り返る?(KPTなどで)← 60分のときに仮締め ## 各自が書き込む場所 >[name=chen] ```javascript= const N = 8 const h = [10,5,12,35,67,88,23,42] const s = [2,1,3,5,3,4,1,6] let t = [0,0,0,0,0,0,0,0] let left = 0 let right = 100 while(right - left > 1){ let mid = (left + right) / 2 let ok = true for(let i = 0 ; i < N ; i++){ // そもそもmidが初期高度より低かったらfalse if(mid < h[i]) ok = false else t[i] = Math.round((mid - h[i]) / s[i]) } console.log('t = ' + t + ', mid = ' + mid) t.sort(function (a, b) { return a - b }) for(let i = 0 ; i < N ; i++){ // 時間切れ発生 if(t[i] < i) ok = false } if(ok) right = Math.round(mid) else left = Math.round(mid) } console.log("right = " + right) console.log("left = " + left) // "t = 20,45,13,3,0,0,27,1, mid = 50" // "t = 33,70,21,8,3,20,52,6, mid = 75" // "t = 39,83,25,11,7,33,65,8, mid = 87.5" // "t = 42,89,27,12,9,2,71,9, mid = 94" // "t = 41,86,26,11,8,1,68,8, mid = 91" // "t = 40,85,26,11,8,0,67,8, mid = 89.5" // "t = 40,84,26,11,7,0,66,8, mid = 89" // "right = 89" // "left = 88" ``` >[name=teruya] https://atcoder.jp/contests/abc023/tasks/abc023_d ![](https://i.imgur.com/WMrQjjS.jpg) ```ruby= # 全体でO(NlogN) def can_score?(score, height_and_speeds) # O(N) left_times = height_and_speeds.map do |height, speed| # 例えばscore(20点)を取りたい時、height(5m)なら、rest_height(15m上昇してもセーフ)となる rest_height = score - height # speed(6)の時、2秒後は17mなのでセーフ、3秒後は23mなのでアウト # なので rest_height(15) / speed(6) = 2 を返す rest_height / speed end # O(NlogN)、ここがボトルネックのオーダー数 # scoreを獲得するためのleft_timeが少ない順(余裕がない順)にソート left_times.sort! puts "score: #{score} を取るためには、それぞれ何秒後までに風船を割れば良いか?↓" p left_times # O(N) # 実際に先頭から順に風船を割っていき、left_timeを超えてしまった風船が1つでもあればfalse can_score = true left_times.each_with_index do |left_time, order| can_score = false if left_time < order end puts "score: #{score} を取ることができるか? #{can_score}" puts can_score end M = 1_000_000_000 * 100_000 n = gets.to_i # 風船の高さと上昇するスピード # [[5, 6], [12, 4], [14, 7], [21, 2]] height_and_speeds = [] n.times { height_and_speeds << gets.split.map(&:to_i) } # 二分探索はO(logM) # 全体でO(NlogNlogM) 100_000 * 15 * 40 みたいなイメージ least_score = (0..M).bsearch { |score| can_score?(score, height_and_speeds) } puts least_score ``` >[name=tsujita] ```ruby= left = 20 right = 36 while (right - left) > 1 do mid = left + (right - left) / 2 puts "Is the age less than #{mid} ? (yes / no)" answer = gets.chomp if answer == 'yes' right = mid else left = mid end end puts "The age is #{left} !" ``` ## 振り返り >[name=chen] うんん...どれの風船か先に打たれる判定が難しいですね :thinking_face: >[name=teruya] `Array#bsearch`便利すぎる さりげなく使ったけど今日は`Range#bsearch`を使いました >[name=tsujita] 動的計画法で鍛えられてました ## 終了後ファシリテーターがやること - 次回のファシリテーターを決める - 大倉さん - 読む範囲を決める - 第7章 貪欲法