Upgrade to Pro — share decks privately, control downloads, hide ads and more …

名状しがたいフローチャートのようなもの

tama
August 16, 2022
200

 名状しがたいフローチャートのようなもの

2022夏合宿研修②

tama

August 16, 2022
Tweet

Transcript

  1. 第1問:Speed Typing • バーバラはスピードタイパーです。⾃分のタイピング速度を 知るために、スピードテストを⾏います。 • スピードテストでは、問題⽂ T という⽂字列を⼊⼒します。 •

    バーバラはスピードテスト中に、キーを押し間違えることが あります。 • しかしタイピング速度を重視するため、間違いを修正するのに余計な 時間をかけたくありません。⼀通り⼊⼒が終わるまで間違いを残した ままタイピングを続けます。 • ⼊⼒を終えた⽂字列を A とします。 • ⼊⼒した⽂字列 A から何⽂字削除すれば正しい回答 T になる でしょうか。 • バーバラはいくつかの⽂字を⾒落としていたり、キーの押し 間違いで⼊⼒していない⽂字があることもあります。 • ⽂字を削除しても A から T にならないときは IMPOSSIBLE と回答して ください。 出典:Kick Start 2022 Round A
  2. ⼿順 ① まず要件を整理する üゴールは何か、何を求めるのか üゴールに⾄るまでのルールは何か、ルールにおける条件は何か ② どんな処理をするか・どんな処理が⾏われるかを考える üまず何をして、次に何をするのか、という処理の流れ ü「〇〇が△ △のときは□

    □する」という判定も考える ③ を付箋に書き出す ④ ⽤紙に付箋を並べて(貼って)処理の流れを吟味する üなるべく上から下に処理が流れるように並べる ü抜けている条件はないか、やるべき処理はすべて書き出せているか、 処理の順序は間違っていないか、判定は意図した通りに書けているか ⑤ フリクションで処理の流れに線を引く ü間違えたときはちゃんと消して書きなおそう 処理 判定 分岐条件 途中で迷⼦にならないように どこかに書き出しておこう!
  3. 要件の整理 • スピードテスト • 問題⽂ T と同じ⽂字列を⼊⼒する • バーバラ •

    スピードテストの途中でキーの押し間違いがある = ⼊⼒値 A と問題⽂ T は異なる⽂字列 • 求める答え • ⼊⼒した⽂字列 A から何⽂字削除すれば正しい回答 T になるか = ⼊⼒値 A を T にするためには何⽂字削除すればよいか • T にならないときは IMPOSSIBLE どの⽂字が押し間違いか、 どの⽂字を修正すればいいか、は聞かれていない!
  4. ⼀番簡単なのは問題⽂ T が1⽂字のとき まず⼀番簡単なケースを考える 仕事はもちろん 何にでも通⽤する考え⽅ ⼊⼒値 A から⽂字を削除して T

    になるのはどんなとき? IMPOSSIBLE になるのはどんなとき? 何⽂字削除すればいい? では⾏うべき判定は? A = “a” A = “zz” A = “abc” A = “xx” A = “xyz” A = “(-x-)” T = “x”
  5. ⼀番簡単なケース:問題⽂ T が1⽂字のとき A の中に T と 同じ⽂字が 含まれているか A

    の⻑さ – 1 を出⼒(回答) IMPOSSIBLE と出⼒(回答) 含まれている 含まれていない ・A を T にするためには 何⽂字削除すればよいか を出⼒する ・T にならないときは IMPOSSIBLE と出⼒する まず要件を書いておく
  6. 分類する 何⽂字か削除すれば T になる:“xxx”、“xxcx”、“xxxx”、“xxzxs” 何⽂字削除しても T にはならない:“xzx”、“cxcsc” キーの押し間違いがない場合:A = “xxx”

    キーの押し間違いがある場合: A = “xxcx”、A = “xxxx”、A = “xzx”、A = “xxzxs”、A = “cxcsc” など 例:T = “xxx” のとき この違いは何? ⼀番簡単な「問題⽂ T が1⽂字のとき」を少し発展させて 問題⽂ T に同じ⽂字しか含まれていないケースで考えてみる 次に簡単なケースを考える
  7. 何を出⼒すればいい? A の⻑さ – T の⻑さ を出⼒(回答) 次に簡単なケース:問題⽂ T に同じ⽂字しか含まれていないとき

    T の⻑さを調べる A の中に T の 1⽂字⽬がいくつ 含まれているか 数える IMPOSSIBLE と出⼒(回答) T の⻑さと同じか それより多い T の⻑さより少ない 次はこれをプログラムに落とし込みたい ・A を T にするためには 何⽂字削除すればよいか を出⼒する ・T にならないときは IMPOSSIBLE と出⼒する
  8. a ≦ A の⻑さ A の何⽂字⽬を調べているかを a 、 A に含まれる

    c の数を n とし、 a = 1⽂字⽬、n = 0⽂字とする A の a 番⽬の⽂字と c を⽐べる a と A の⻑さを⽐べる T の1⽂字⽬を c とする n を +1 する a > A の⻑さ 同じ⽂字 違う⽂字 a を +1 する IMPOSSIBLE と出⼒(回答) n と T の⻑さを⽐べる A の⻑さ – T の⻑さ を出⼒(回答) n ≧ T の⻑さ n < T の⻑さ A を調べきった まだ調べていない⽂字がある T の⻑さと同じか それより多い c がある プログラムっぽく:問題⽂ T に同じ⽂字しか含まれていないとき ・A を T にするためには 何⽂字削除すればよいか を出⼒する ・T にならないときは IMPOSSIBLE と出⼒する
  9. まずイメージ:問題⽂ T にさまざまな⽂字が含まれているとき ⼀番簡単なケースで考えた、 • IMPOSSIBLE になるのはどんなとき? • ⼊⼒値 A

    から⽂字を削除して T になるのはどんなとき? • 何⽂字削除すればいい? を考えないといけない。 少なくとも A の⻑さが T の⻑さと同じか それ以上ないといけない T の⽂字が A の中に すべて含まれて いないといけない T の⽂字が順番通りに A の中にすべて含まれて いないといけない それだけでなく もっと⾔えば 【⽅針】 T と A をそれぞれ先頭から順に1⽂字ずつ調べ、 T を構成する⽂字がすべて A の中に含まれているかを確認する
  10. ・A を T にするためには 何⽂字削除すればよいか を出⼒する ・T にならないときは IMPOSSIBLE と出⼒する

    難しいケース:問題⽂ T にさまざまな⽂字が含まれているとき T の何⽂字⽬を調べているかを t 、 A の何⽂字⽬を調べているかを a とし、 t = a = 1⽂字⽬とする T の t 番⽬の⽂字と A の a 番⽬の⽂字を⽐べる t と T の⻑さを⽐べる t を +1、a も +1 する (T と A を次の⽂字に進める) A の⻑さ – T の⻑さ を出⼒(回答) t ≦ T の⻑さ t > T の⻑さ 同じ⽂字 T を調べきった まだ調べていない⽂字がある
  11. T の t 番⽬の⽂字と A の a 番⽬の⽂字を⽐べる a と

    A の⻑さを⽐べる a を +1 する (A だけ次の⽂字に進める) t を +1、a も +1 する (T と A を次の⽂字に進める) a > A の⻑さ IMPOSSIBLE と出⼒(回答) A の⻑さ – T の⻑さ を出⼒(回答) a ≦ A の⻑さ t ≦ T の⻑さ 同じ⽂字 違う⽂字 まだ調べていない⽂字がある A を調べきった t と T の⻑さを⽐べる まだ調べていない⽂字がある 難しいケース:問題⽂ T にさまざまな⽂字が含まれているとき t > T の⻑さ T を調べきった T の何⽂字⽬を調べているかを t 、 A の何⽂字⽬を調べているかを a とし、 t = a = 1⽂字⽬とする ・A を T にするためには 何⽂字削除すればよいか を出⼒する ・T にならないときは IMPOSSIBLE と出⼒する
  12. 第2問:Oversized Pancake Flipper • 鉄板の上でパンケーキを並べて焼いている • 横⻑の特⼤フリッパー(コテ)で N枚をまとめて、場所はそ のままひっくり返す •

    端っこでも N枚まとめてひっくり返す必要がある • 最低何回ひっくり返せば、鉄板の上のパンケーキがすべて “Happy side”(が上を向く)になるか • またはそれができないときは IMPOSSIBLE と答える Happy side Blank side Happy side Blank side 例:N = 3 のとき N枚(=3枚)まとめて上下反転
  13. まず⼀番簡単なケースを考える 第1問:Speed Typing と同じ この問題で(次につながる)⼀番簡単なケースは N=1 すなわちパンケーキ1枚しかひっくり返せないコテを使うケース となりのパンケーキのことを気にせず Blank side

    のパンケーキをすべてひっくり返せばいい しかし 「Blank side のパンケーキをすべてひっくり返して」 という指⽰は抽象的すぎるのでもう少し詳しく考える ⼀列に 1,000 枚のパンケーキが並んでいる場合を考えると 「⽬についた Blank side からどんどんひっくり返す」では効率が悪い せっかく⼀列に並んでいるので、端から1枚ずつ順番に⾒ていく
  14. x ≦ パンケーキの枚数 端から x 枚⽬のパンケーキが 表か裏か調べる x とパンケーキの枚数を⽐べる 端から

    x 枚⽬のパンケーキを ひっくり返して c を +1 する x > パンケーキの枚数 x を +1 する c(ひっくり返した回数) を出⼒(回答) すべてのパンケーキを 調べきった まだ調べていない パンケーキがある 「ひっくり返す」という操作を プログラム的に書く場合は、⾔語に よっていろいろな書き⽅があるが、 いずれにしても関数に切り出せばよい。 アルゴリズムの本質からは逸れるので、 ここでは「ひっくり返す」という 表現に留めておく 複雑な処理でも流れ(フロー)の 本質を追うときは、細かい作業は 集約して考えるのがコツ ひっくり返した回数を c で表す c = 0(0回)から始める 端から何枚⽬のパンケーキに 注⽬しているかを x で表す x = 1(端から1枚⽬)から始める ・何回ひっくり返せばすべての パンケーキが Happy side を 向くかを出⼒する ・すべて Happy side にできない ときは IMPOSSIBLE と出⼒する Blank side Happy side N=1 のときは必ず すべてのパンケーキを Happy side にすることが できるので IMPOSSIBLE を 出⼒することはない
  15. N > 1 になったらどうなる? N=2 でこうなっていたらすべて Happy side にすることはできない =

    IMPOSSIBLE パンケーキの状態はふたつ (Happy side/Blank side)なので 同じ場所で2回ひっくり返すと 元と同じ状態に戻ってしまう(右図) ① ② ③ ④ ⑤ 同じ場所でひっくり返すのは 最⼤1回でいい N=1 の場合と同じように 端から順に1枚ずつ⾒ていく = 端から順に Happy side にしていく 同じ場所を2回ずつひっくり返すと元と同じ状態になる
  16. x 枚⽬以のパンケーキの中に Blank side があるか確認する x + N - 1

    ≦ パンケーキの枚数 ひっくり返した回数を c で表す c = 0(0回)から始める 端から x 枚⽬のパンケーキが 表か裏か調べる x + N - 1 とパンケーキの枚数を⽐べる 端から何枚⽬のパンケーキに 注⽬しているかを x で表す x = 1(端から1枚⽬)から始める x 枚⽬からN枚のパンケーキを ひっくり返して c を +1 する x + N - 1 > パンケーキの枚数 Blank side Happy side x を +1 する c(ひっくり返した回数) を出⼒(回答) すべてのパンケーキを 調べきった まだ調べていない パンケーキがある Nとパンキーキの枚数を⽐べる N ≦ パンケーキの枚数 N > パンケーキの枚数 IMPOSSIBLE と出⼒(回答) Blank side のパンケーキがある Blank side のパンケーキはない ・何回ひっくり返せばすべての パンケーキが Happy side を 向くかを出⼒する ・すべて Happy side にできない ときは IMPOSSIBLE と出⼒する x を含めて N枚返せるコテを 使うので、⼀度に返せるのは x(+ 0)枚⽬、x + 1枚⽬、 x + 2枚⽬、… x + N - 1枚⽬のN枚。 このとき終端にある x + N - 1 が パンケーキの枚数を 超えてはいけない 2ページ前の N=1 のケースと どこが変わっているか ⾒⽐べてみてください このフローは N=1 のときも 動くので、N=1 を代⼊すると 2ページ前と同じ フローになるはず… x 枚⽬以降のパンケーキ =「残りのパンケーキ」
  17. 第3問:Revenge of the Pancakes • ⽚⾯が “Happy side”、もう⽚⾯が “Blank side”

    のパンケーキ • お⽫に積み重ねられたパンケーキの上のほうを持ち上げて、 ⼀気に(持ち上げた全体を)ひっくり返す • 最低何回ひっくり返せば、お⽫の上のパンケーキがすべて “Happy side” になるか(“Happy side” が上を向く) Happy side Blank side 例: Happy Happy Blank Blank Happy Blank Happy Blank Blank Blank Happy Blank
  18. 考え⽅ すますさんがコップを重ねていた「ひとかたまりにする」 最終的なゴールは「すべて Happy side にする」 その⼿前に 「すべて同じ向きに揃える」 という⽬標を考える すべて

    Happy side 向きになった ⇒ 完了 すべて Blank side 向きになった ⇒ 全体を引っくり返す(+1回) 向きを揃えている間は、 それぞれのパンケーキが Happy side を向いているか/ Blank side を向いているかは 関係ない(気にしなくてよい) Blank side になるような ひっくり返し⽅を することに臆する 必要はない
  19. 「すべて同じ向きに揃える」ためにどうするか Happy side Blank side Blank side Happy side Blank

    side 第2問の「端から1枚ずつ順番に⾒ていく」を思い出す ・この問題における「端」とは ⼀番上のパンケーキのこと ・⼀番下ではダメなのか それより上に載っているパンケーキが すべてひっくり返す対象になってしまうので コントロールしづらい どうやって揃えるか 【⽅針】 上から順に⾒ていき、⾯(向き)が変わるところで それより上のパンケーキをひっくり返す ⇒ これによりパンケーキの⾯(向き)が揃う Blank side Blank side Blank side Happy side Blank side Happy side Happy side Happy side Happy side Blank side Blank side Blank side Blank side Blank side Blank side ② ③ ④ ⑤ ① Happy side Happy side Happy side Happy side Happy side
  20. パンケーキ(全体)が どちらを向いているか 確認する y とパンケーキの枚数を⽐べる c を +1 する y

    < パンケーキの枚数 c(ひっくり返した回数) を出⼒(回答) まだ次の パンケーキ がある ひっくり返した回数を c で表す c = 0(0回)から始める 上から何枚⽬のパンケーキに 注⽬しているかを y で表す y = 1(上から1枚⽬)から始める ・何回ひっくり返せばすべての パンケーキが Happy side を 向くかを出⼒する Blank side Happy side y = パンケーキの枚数 今の(上から y 枚⽬の) パンケーキと 次の(上から y + 1 枚⽬の) パンケーキを を⽐べる c を +1 する y を +1 する これが最後のパンケーキ 違う向き 同じ向き 上から y 枚の パンケーキを ひっくり返す すべての パンケーキを ひっくり返す 左半分は 「すべて同じ向きに揃える」 ためのフロー
  21. 出典 • 第1問:Speed Typing(Kick Start 2022 Round A) • 第2問:

    Oversized Pancake Flipper(Code Jam 2017 QR) • 第3問: Revenge of the Pancakes(Code Jam 2016 QR) • Code Jam には Infinite House of Pancakes シリーズ(勝⼿にこう 呼んでる)の作品(?)たちがこんなにも • Infinite House of Pancakes(Code Jam 2015 QR) • Revenge of the Pancakes(Code Jam 2016 QR) • Oversized Pancake Flipper(Code Jam 2017 QR) • Ample Syrup(Code Jam 2017 Round 1C) • Waffle Choppers(Code Jam 2018 Round 1A) • Pancake Pyramid(Code Jam 2019 Round 3) • Oversized Pancake Choppers(Code Jam 2020 Round 1C) • Pancake Deque(Code Jam 2022 Round 1B)
  22. ふりかえり • 思いのほかみんな苦戦していたな、と思いました • 答えを聞いたら(解説を読んだら)理解ができる、としたら、⾃分が どこに詰まっていたのか考えてみましょう • 考え⽅⾃体が思いつかなかったのか、フローに表現できなかったのか • フローを⾒て、少し説明を聞いて理解・納得できるなら⼗分です

    • 慣れていけば⾃分でフローを作れるようになるでしょう • 必要以上に処理を難しくしていませんか • シンプルに書ける処理を、難しく考えすぎて、あるいは処理の本質が ⾒極められなくて、難しく複雑にしてしまっていませんか • 複雑にすればするほどレビューも改修も⼤変になるので、やるべきこ とを⾒極めてよりシンプルに、本質にアプローチしましょう • プログラマー以外にもアルゴリズム⼒は必要です • ⼩学校の「プログラミング教育」はコードの書き⽅の説明ではなく、 こういうアルゴリズム⼒を鍛えるためのものです • ツールは問わないので、ぜひフローを書いていってください • 処理の流れ、境界値や条件、確認すべき値などが⾒えてきます • いろんな境界値を調べないといけない話は研修③でもしました