30代SEの自由帳

最初のタイトルは頓挫した

ヒューマン・リソース・マシーン 攻略 入社28年目 小から大へ

ここで解説している内容なりヒントなりはあくまで筆者の解法に基づいたものなので、別の考え方ももちろんあるよ。ってのは念頭に置いてください。

課題

左側の数値3つごとに対して、小さい順に並べ替え、右側へ運んでください。

使用可能な命令

  • inbox
  • outbox
  • copyfrom
  • copyto
  • add
  • sub
  • bump+
  • bump-
  • jump
  • jump_if_zero
  • jump_if_neg

効率目標

  • サイズ:34行
  • スピード:78ステップ

ヒント

その1

ただ愚直に場合分けをすればよい。

その2(サイズ目標)

最初の1回分を並び変えて共通化するだけで、場合分けが1ケース分削れる。

その3(サイズ目標)

Aを初めから2箇所に設定しておくと並び替え用に一時保持する必要がなくなる。

回答例 + 解説

スピード

回答例 + 解説

1. jump:ラベル1へ
ラベル2// 手元のパネルを運んでからAを右に運ぶ
2. outbox
3. copyfrom A
ラベル3:// 右に運ぶ
4. outbox
ラベル1// 1セットの開始位置
5. inbox
6. copyto A
7. inbox
8. copyto B
9. sub A
10. jump_if_neg:ラベル4// A < B
11. inbox
12. copyto C
13. sub A
14. jump_if_neg:ラベル5// Aが最小
15. copyfrom A
16. outbox
17. copyfrom C
18. sub B
19. jump_if_neg:ラベル6// A < B < C
20. copyfrom B
21. outbox
22. copyfrom C
23. jump:ラベル3へ
ラベル6// A < C < B
24. copyfrom C
25. outbox
26. copyfrom B
27. jump:ラベル3へ
ラベル5// C < A < B
28. copyfrom C
29. outbox
30. copyfrom A
31. outbox
32. copyfrom B
33. jump:ラベル3へ
ラベル4// B < A
34. inbox
35. copyto C
36. sub B
37. jump_if_neg:ラベル7// Bが最小
38. copyfrom B
39. outbox
40. copyfrom C
41. sub A
42. jump_if_neg:ラベル8// B < A < C
43. copyfrom A
44. outbox
45. copyfrom C
46. jump:ラベル3へ
ラベル8// B < C < A
47. copyfrom C
48. jump:ラベル2へ
ラベル7// C < B < A
49. copyfrom C
50. outbox
51. copyfrom B
52. jump:ラベル2

ただただ愚直に場合分けして組むだけ。

左のパネルを取って(inbox)、Aとして保持(copyto)
次のパネルを取って(inbox)、Bとして保持(copyto)
AとBを比較(sub)して、Aの方が大きければ(jump_if_neg)B < Aへ
そうじゃなければA < Bへ * A < B 次のパネルを取って(inbox)、Cとして保持(copyto) AとCを比較(sub)して、Aの方が大きければ(jump_if_neg)、C < A < Bが確定なので、その順番で運ぶ(copyfrom -> outbox)
そうじゃなければ、Aが最小であることは確定なので、まずA(copyfrom)を運ぶ(outbox)
その後、BとCを比較してBの方が大きければ(jump_if_neg)、C < B、そうじゃなければB < Cで確定なので、それぞれその順番で運ぶ(copyfrom -> outbox)
* B < A 上記[A < B]のAとBを入れ替えて同じ処理を実施

上記例はサイズ目標を見越して同じ処理は極力まとめてしまっているから分かり難いかも。。

サイズ

回答例 + 解説

1. jump:ラベル1へ
ラベル2// 手元のパネルを運んでからBを右に運ぶ
2. outbox
3. copyfrom B
ラベル3:// 右に運ぶ
4. outbox
ラベル1// 1セットの開始位置
5. inbox
6. copyto A
7. copyto B
8. inbox
9. sub A
10. jump_if_neg:ラベル4// A < B
11. add A
12. copyto B
13. jump:ラベル414. add A
15. copyto A
ラベル4:AとCの比較
16. inbox
17. copyto C
18. sub A
19. jump_if_neg:ラベル5// Aが最小
20. copyfrom A
21. outbox
22. copyfrom C
23. sub B
24. jump_if_neg:ラベル6// A < B < C
25. copyfrom B
26. outbox
27. copyfrom C
28. jump:ラベル3へ
ラベル6// A < C < B
29. copyfrom C
30. jump:ラベル2へ
ラベル5// C < A < B
31. copyfrom C
32. outbox
33. copyfrom A
34. jump:ラベル2

上記解法でスピード目標を満たしている前提。
最初の1回分を並び替えて共通化することで、B < Aの場合分けをごっそり削除。
この時、Aを2箇所に設定しておくことで、いざB < Aとなったときに並び替え用に一時領域にAを保持。といったことをする必要がなくなる。

また、A < Bの形に整形することに伴って、処理最初の方で、inboxに繋げるoutboxに不随するcopyfromはBに変更。
※A < Bの形に整形した場合、パターンとしてC < A < B / A < C < B / A < B < Cの3パターンのみとなり、最終項がBになるケースが最多となるため

左のパネルを取って(inbox)、AとBに保持(copyto) 次のパネルを取って(inbox)、前に取ったパネルと比較(sub)し、前のパネルの方が大きければ(jump_if_neg)、Aとして保持(copyto)
そうじゃなければBとして保持(copyto)する。
この時、手元のパネル自体は計算結果となっているため、減算していた値を加算(add)することで元の値を復元してから保持する。

あとは上記スピード目標のA < Bのケースと同様

  

<前:26年目> <目次> <次:29年目>