蟻本読もうぜ(^~^)?

もさもさもさもさもさもさ(^~^) 公開下書き

蟻本読もうぜ(^~^)?

20210124shogi2a2b1.png
「 👇 蟻本読もうぜ?」

📖 プログラミングコンテストチャレンジブック [第2版] ~問題解決のアルゴリズム活用力とコーディングテクニックを鍛える~ Kindle Edition

kifuwarabe-futsu.png
「 読み終わったら教えてくれだぜ」

ohkina-hiyoko-futsu.png
「 蟻本読まないと ABC の D問題に出てくる DP が分かんないのよ」

kifuwarabe-futsu.png
「 アルファベットばかりで分けわからん」

ramen-tabero-futsu2.png
「 👆 ソースコードとか ダウンロードできないものか」

📖 「プログラミングコンテストチャレンジブック第2版」サポートサイト

ramen-tabero-futsu2.png
「 👆 正誤表が載ってるだけかだぜ」

ramen-tabero-futsu2.png
「 動かして試したいんだが、自分で打鍵するしかないのか」

ohkina-hiyoko-futsu.png
「 それがプログラミング・コンテストよ」

ramen-tabero-futsu2.png
「 アルゴリズムに著作権は無いから バンバン ブログに書いてもいいと思うんだが、どんなパンチが飛んでくるか分からないんで 手元でこっそり動かすかだぜ」

📖 コードテスト(C++入門 AtCoder Programming Guide for beginners (APG4b))

ramen-tabero-futsu2.png
「 👆 コードテストって、練習に勝手に使っていいのかだぜ?」

kifuwarabe-futsu.png
「 お父んみたいなやつがマジョリティーになって社会問題になったら AtCoder も腰を上げるだろ」

ramen-tabero-futsu2.png
「 蟻本のコードは G++ だから APG4b のサンプルの GCC と違うのな。
ちょっと読み替えないといけないな」

Chapter 1

P8

20210614blog17.png

ramen-tabero-futsu2.png
「 よし、ちょっと読み替えて、動くぜ」

ohkina-hiyoko-futsu.png
「 ちゃんと理解してやってんの?」

ramen-tabero-futsu2.png
「 理解しようとして手が止まってしまうよりは、コードを真似て動かして進もうぜ?」

P21

ramen-tabero-futsu2.png
「 C++の for文って 打鍵量多いから やっぱ rep(i, N) だよな」

ramen-tabero-futsu2.png
「 👇 テンプレート作っとこ」

P

Test1:


// 実行時間とメモリ: ms KB

Test2:


// 実行時間とメモリ: ms KB
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

// 制約
const int MAX_N = 100;

// 入力
int n, a[MAX_N];

void solve() {
}

int main() {
  // 標準入力より入力
  cin >> n;
  rep(i, n) {
    cin >> a[i];
  }

  solve();
}

P23

ramen-tabero-futsu2.png
「 この蟻本、 POJ からの引用なのだったら、わたしが引用してもいいのでは?」

kifuwarabe-futsu.png
「 そんな推移律が成り立つのかだぜ?」

📖 北京大学(POJ)

ramen-tabero-futsu2.png
「 👆 大学なのか。
中国で著作権の取り扱いがどうなってんのか分かんね」

    // 抜粋
    minT = max(minT, min(x[i], L-x[i]));

ohkina-hiyoko-futsu.png
「 👆 最小の時間を計算、と言ってるのに なんで min( ) ではなく max( ) なの?」

ramen-tabero-futsu2.png
「 図を描かないと 分かんないよな」

20210615coder18.png

ramen-tabero-futsu2.png
「 👆 例えば 長さ 5 の棒って こんな感じ」

20210615coder18a1.png

ramen-tabero-futsu2.png
「 👆 全長が 5 で、蟻が 3 に居れば、
蟻の左側の長さは 3 で、右側は L - 3 だな」

20210615coder18a2.png

ohkina-hiyoko-futsu.png
「 👆 min を取ると 長さが短い方を取るのは わかるのよ」

20210615coder18a3.png

ramen-tabero-futsu2.png
「 👆 最小の時間を取るといったら、上図のどっちだぜ?」

ohkina-hiyoko-futsu.png
「 時間がかかって足が引っ張ってしまう方を取るから 上図の上のバーね」

kifuwarabe-futsu.png
「 最小の時間を取るという話しをしているのに、なんで 時間がかかる方を取るんだぜ?」

ramen-tabero-futsu2.png
「 全体として最小になる時間を取ろう、と言っているんだぜ」

ramen-tabero-futsu2.png
「 部分としては max 関数を使って 時間がかかる方を取る場面もあるということだな」

P25

xより小さければ、xはあるなら半分より後ろにある

ohkina-hiyoko-futsu.png
「 👆 日本語が分けわかんない」

ramen-tabero-futsu2.png
「 日本語はワケ分かんないが、二分探索は知ってるんで あとで説明するぜ」

二分探索

kの中央の数字

ohkina-hiyoko-futsu.png
「 👆 って何なの?」

20210616coder19.png

ramen-tabero-futsu2.png
「 👆 例えば、数字の4を折り曲げれると思ってくれだぜ。
このとき、折り目は2だぜ。この2を 中央の数字 と呼んでいる」

ohkina-hiyoko-futsu.png
「 でも 数列はバラバラよ。例えば 2, 3, 9, 11, 105 とか」

20210616coder19a1.png

ramen-tabero-futsu2.png
「 👆 そのような数列でもイケる。昇順か、降順に並んでさえいれば」

偶数個の場合

ohkina-hiyoko-futsu.png
「 👆 って何なの?」

20210616coder20.png

ramen-tabero-futsu2.png
「 👆 数字が偶数個の場合、長さを2で割ると 0.5 余るから切り捨てて、
下の方が短めの、真ん中から 0.5 ずれたところが 折り目になるな」

kifuwarabe-futsu.png
「 めんどくせ」

20210616coder19a2.png

ramen-tabero-futsu2.png
「 👆 x というのは探したいものだぜ。
棒の上にあるかもしれないし、ないかもしれない」

xより小さければ、xはあるなら半分より後ろにある

↓
xより 「中央の数字が」 小さければ、xはあるなら 「半分」 より後ろにある

ohkina-hiyoko-futsu.png
「 👆 うーん、日本語が釈然としないなあ」

20210616coder20a2.png

ramen-tabero-futsu2.png
「 👆 半分 とか 中央の数字 とか ワケ分かんないんで、
折り目と、折り目んとこにある数字 と考えろだぜ」

ohkina-hiyoko-futsu.png
「 xは 無いこともあるの?」

ramen-tabero-futsu2.png
「 xは、有ったり無かったりする」

20210616coder21.png

ramen-tabero-futsu2.png
「 👆 例えば xが100だったら、上図の棒には x は無いぜ」

kifuwarabe-futsu.png
「 なんということだぜ」

O(log n)

ohkina-hiyoko-futsu.png
「 log n って何なの?」

ramen-tabero-futsu2.png
「 倍々ゲームの速さだが……」

20210617coder22a1.png

ramen-tabero-futsu2.png
「 👆 log の右下に小さく 倍々の速度を書くのが本来だぜ。この右下の数字を 底(てい)と呼ぶ。
競技プログラミングでは 底は 2 を使うんで 省略しているそうだぜ」

kifuwarabe-futsu.png
「 倍々の速度って何だぜ?」

20210617coder23.png

ramen-tabero-futsu2.png
「 👆 緑色の数は 2倍、2倍で増えていっているが、 log2 緑色の数 と書くと、赤色の数 が出てくる表引きだと思ってくれだぜ」

ohkina-hiyoko-futsu.png
「 log2 って どうやって筆算すんの?」

ramen-tabero-futsu2.png
「 筆算しない。表引き」

20210617coder23a1.png

ramen-tabero-futsu2.png
「 👆 指数の逆のことだと感じろだぜ」

kifuwarabe-futsu.png
「 128を 2 で何回割れるかということかだぜ」

ramen-tabero-futsu2.png
「 そうだぜ」

二分探索の計算量は O(log n)

20210617coder24.png

ramen-tabero-futsu2.png
「 👆 二分探索の動きを絵にしたぜ。同じことを3回してるよな」

kifuwarabe-futsu.png
「 半分より1個多く 折ってる気がするが……」

20210617coder25.png

ramen-tabero-futsu2.png
「 👆 長さが8のとき、3回折ったら xがあるなら、xを見つけてるだろ」

ohkina-hiyoko-futsu.png
「 その聞きなれない日本語を止めなさい」

kifuwarabe-futsu.png
「 長さが7のときも試してくれだぜ」

ramen-tabero-futsu2.png
「 境界値チェックか。やったろ」

20210617coder26.png

kifuwarabe-futsu.png
「 👆 さっきと同じ 3回だぜ」

20210617coder27.png

kifuwarabe-futsu.png
「 👆 2.8073… 回じゃないのかだぜ!」

ramen-tabero-futsu2.png
「 小数点以下切上げだろ」

20210617coder28.png

ohkina-hiyoko-futsu.png
「 👆 この茶番は確かに 切り上げ なのよ。 xが折り目にくるまで 3回かかるわ」

ソートにO(n log n)

ソートにO(n log n)時間

ohkina-hiyoko-futsu.png
「 👆 なんのこっちゃ」

20210617coder30.png

ramen-tabero-futsu2.png
「 👆 ソートというのは 並び替えのことだが……」

20210617coder30a1.png

ramen-tabero-futsu2.png
「 👆 並び替える必要がないときはすぐ終わるし、最悪のケースでは たくさん 操作があるぜ」

ramen-tabero-futsu2.png
「 ライブラリなどに実装されている、配列の要素の並び替えの操作にかかる時間のオーダーは 最悪のケースで O(n log n) と言われているんだぜ」

ohkina-hiyoko-futsu.png
「 n log n が何かって聞いてんのよ」

20210617coder29.png

ramen-tabero-futsu2.png
「 👆 n って要素数だから、1つの要素ごとに log n の計算量をさばいているということだぜ。
最悪のケースで」

ramen-tabero-futsu2.png
「 n log n の左側の n の意味としては、要素数が増えれば それだけ単純な掛け算として 時間がかかりますよ、ということだぜ。
右側の n は 対数時間だな。 対数時間というのは 指数時間の逆のようなものだぜ。さっきやった」

ramen-tabero-futsu2.png
「 もっと時間のかかるソートもあるが、今どきのプログラム言語でソートといえば O(n log n) でしょ、ということだぜ」

ループにO(n^3 log n)

ループにO(n^3 log n)時間

ohkina-hiyoko-futsu.png
「 👆 なんのこっちゃ」

ramen-tabero-futsu2.png
「 最悪のケースで、全件探索を3回しながら log n の計算量の処理をするということだぜ」

20210617coder31.png

ramen-tabero-futsu2.png
「 👆 n=3 が 3個あるのを、例えば上図のように描いてみようぜ?」

20210617coder31a1.png

ramen-tabero-futsu2.png
「 👆 例えば 住所に例えれば 0県0市 みたいに階層になっていると考えろだぜ」

20210617coder31a2.png

ramen-tabero-futsu2.png
「 👆 3階層あれば 0県0市0区だな……、あれ? なんか多くね?」

kifuwarabe-futsu.png
「 お父んが勝手に 0 から数を振ってるから、n は 3 ではなくて、実際には 4 だな」

ramen-tabero-futsu2.png
「 このように、 1重ループなら n、 2重ループなら n×n、 3重ループなら n×n×n だぜ」

P26

8ms --> 8ms
408KB --> 336KB

7ms --> 6ms
452KB --> 352KB

kifuwarabe-futsu.png
「 👆 バイナリーサーチにしたら、微妙に速くなったかな?」

ramen-tabero-futsu2.png
「 件数が小さいうちは 美味さが分からん……」

        // rep(d, n) {
        //   if (k[a] + k[b] + k[c] + k[d] == m) {

        ↓

        // if (binary_search(m - k[a] - k[b] - k[c])) {

ohkina-hiyoko-futsu.png
「 👆 何でこれが 等しいのか 説明読んでも分かんないんだけど?」

ramen-tabero-futsu2.png
「 絵にして説明しよう」

20210617coder32.png

ramen-tabero-futsu2.png
「 👆 長さが1,3、5 の棒が いくつでもあるとき、 4本使って 長さ10 にしたいとしよう」

kifuwarabe-futsu.png
「 3 × 3 × 3 × 3 で 81 パターンあるぜ」

20210617coder32a1.png

ramen-tabero-futsu2.png
「 👆 4重ループを使えば 総当たりできるな」

20210617coder32a2.png

ramen-tabero-futsu2.png
「 👆 例えば ピッタリ行くパターンはこれだぜ。 他にもあるな」

ohkina-hiyoko-futsu.png
「 それがなんで m から Ka、Kb、Kc を引いていく 引き算になるの?」

20210617coder32a3.png

ramen-tabero-futsu2.png
「 👆 この Kd のループを、 O(n) から O(log n) に縮めたいんだぜ」

kifuwarabe-futsu.png
「 長さが 5 の棒と、バイナリーサーチの 何が関係あるんだぜ?」

20210617coder33.png

ramen-tabero-futsu2.png
「 👆 バイナリーサーチするのは 当てはめる棒の方だぜ」

kifuwarabe-futsu.png
「 3本ぐらい バイナリーサーチしても おいしくないんじゃないかだぜ?」

制約
1 <= n <= 50

ramen-tabero-futsu2.png
「 👆 3本が 50本に増えても まだ大したことないかもしれないが、 1000本に増えると ダメらしいぜ」

3
10
1 3 5

ohkina-hiyoko-futsu.png
「 👆 どうやって n=1000 のケース作んの? 大変よ?」

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

int main() {
  cout << "3" << endl;
  cout << "4000" << endl;

  rep(i, 1000) {
    cout << i << " ";
  }
  cout << endl;
}

ramen-tabero-futsu2.png
「 👆 コードテストが目の前にあるんで使おうぜ? テスト考えるの大変だけど」

20210617coder34.png

ramen-tabero-futsu2.png
「 ほら イケた」

20210617coder35a1.png

kifuwarabe-futsu.png
「 👆 イケてないぜ」

#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

int main() {
  /*
  cout << "3" << endl;
  cout << "4000" << endl;

  rep(i, 500) {
    cout << i << " ";
  }
  // */
  // /*
  rep(i, 500) {
    cout << i + 501 << " ";
  }
  // */

  cout << endl;
}

ramen-tabero-futsu2.png
「 👆 2パートに分けろだぜ!」

20210617coder36.png

kifuwarabe-futsu.png
「 👆 4重ループぐらい簡単にイケるみたいだぜ?」

ohkina-hiyoko-futsu.png
「 n=3 を n=1000 に変えないとダメなんじゃないの?」

20210617coder37.png

kifuwarabe-futsu.png
「 👆 n=1000 ぐらい簡単にイケるみたいだぜ?」

// 制約
const int MAX_N = 50;

// 入力
int n, m, k[MAX_N];

ramen-tabero-futsu2.png
「 👆 あれっ? 配列のサイズをオーバーするエラーになるんじゃないのかだぜ?
これでエラーにならなかった理由は不明。 MAX_N を 1000 にしたろ」

20210617coder38.png

ramen-tabero-futsu2.png
「 よし エラーになったぜ」

kifuwarabe-futsu.png
「 じゃあ バイナリーサーチを使ってみてくれだぜ」

O(n^3 log n)

20210617coder39.png

ramen-tabero-futsu2.png
「 👆 62ms になったぜ」

ohkina-hiyoko-futsu.png
「 こりゃ バイナリーサーチ使うわね」

kifuwarabe-futsu.png
「 ループが3つで O(n^3)、 バイナリーサーチ1つで O(n log n) として、 O(n^3 log n) だな」

ramen-tabero-futsu2.png
「 蟻本の想定しているCPUって何だぜ? Ryzen Threadripper 12 Core 使ってるから  O(n^3 log n) の計算 n=1000 で 早く終わってしまったのかだぜ?」

20210617coder42.png

kifuwarabe-futsu.png
「 いや、お父んが コピー貼り付けで MAX_N = 50 に戻したからだぜ」

ramen-tabero-futsu2.png
「 アカンのか……」

O(n^2 log n)

20210617coder40.png

ramen-tabero-futsu2.png
「 👆 O(n^3 log n) の計算ではまだ遅いんで、 O(n^2 log n) にしようぜ、という話しだぜ」

kifuwarabe-futsu.png
「 そんなこと できたらいいな、だが どうやってだぜ?」

20210617coder41.png

ramen-tabero-futsu2.png
「 👆 KcKd のパターンを1つにしてしまうんだぜ」

ohkina-hiyoko-futsu.png
「 そうすりゃ できそうねぇ」

20210617coder43.png

ramen-tabero-futsu2.png
「 👆 やっと通った、つら」

Chapter 2

ramen-tabero-futsu2.png
「 簡単なページは飛ばしていこうぜ」

P34

kifuwarabe-futsu.png
「 木構造で 何やってんだぜ?」

20210617coder44.png

ramen-tabero-futsu2.png
「 👆 main 関数で dfs(0, 0) と書いているな。これを上図で示した」

20210617coder44a1.png

ramen-tabero-futsu2.png
「 👆 で、 sum が増えない出口と、 sum が増える出口 の計2つの出口があるんだぜ」

20210617coder45.png

ramen-tabero-futsu2.png
「 👆 あとは 葉っぱ まで 潜って行けだぜ」

kifuwarabe-futsu.png
「 潜って何をやってるんだぜ?」

20210617coder45a1.png

ramen-tabero-futsu2.png
「 👆 sum の全パターンを作ったわけだな」

ohkina-hiyoko-futsu.png
「 13 を探していたのよね~」

20210617coder45a2.png

ramen-tabero-futsu2.png
「 👆 13 は、 +2、 +4、 +7 で作れるみたいだな」

20210617coder45a3.png

ramen-tabero-futsu2.png
「 👆 戻るときは True か False を返してこいだぜ。 True が優先」

20210617coder45a6.png

ramen-tabero-futsu2.png
「 👆 DFS(Depth-First Search; 深さ優先探索)だから、上図のように潜ったり浮かんだりするんだろうけど」

P35

kifuwarabe-futsu.png
「 コンピューター囲碁の連(れん)を見つけるアルゴリズムだ」

ramen-tabero-futsu2.png
「 また書かされるのか」

ohkina-hiyoko-futsu.png
「 これって DFS(Depth-First Search; 深さ優先探索)だったの?」

ramen-tabero-futsu2.png
「 そんな分類なんだな。 お部屋のお掃除 ぐらいにしか思ってなかったぜ」

kifuwarabe-futsu.png
「 その捉え方だと ロジックが弱いから 類型問題の連想に結びつかないんじゃないか?」

ramen-tabero-futsu2.png
「 いろいろなお部屋のお掃除 があるもんな」

20210618coder46.png

ramen-tabero-futsu2.png
「 👆 これにも名前が付いているのかだぜ?
横が m サイズ、 楯が n サイズの盤を 全マス スキャンするんだぜ」

kifuwarabe-futsu.png
「 お父んは 何と呼んでるんだぜ?」

ramen-tabero-futsu2.png
「 スキャン だぜ」

ohkina-hiyoko-futsu.png
「 特に呼び名は内容ねぇ。 強いて言えば 2重ループかしら」

ohkina-hiyoko-futsu.png
「 蟻本のサンプルは 縦方向の2重ループだけど、
漏れなく全マス見るようね。 オーダーは O(N × M)

20210618coder47a2.png

ramen-tabero-futsu2.png
「 👆 蟻本では 8方向と言っているが、9マス調べているぜ。
調べ終わったマスは .(ドット)で塗りつぶしていくから、
それでも 同じマスを何度も調べるような不具合は出ないんだな」

20210618coder48a1.png

ramen-tabero-futsu2.png
「 👆 あれっ、思ってたのと違う!」

kifuwarabe-futsu.png
「 問題文をよく読めだぜ」

20210618coder49.png

ramen-tabero-futsu2.png
「 👆 水溜まりの数は 13個 じゃないのかだぜ!」

20210618coder49a2.png

ohkina-hiyoko-futsu.png
「 👆 31個よ」

ramen-tabero-futsu2.png
「 ぬぎぎぎぎ!」

kifuwarabe-futsu.png
「 勝手に 水溜まりを くっつけるなだぜ」

ramen-tabero-futsu2.png
「 ぬぎぎぎぎぎぎ!」

P36

状態を探索します。

ohkina-hiyoko-futsu.png
「 👆 状態 って何なの?」

20210618coder51a1.png

ramen-tabero-futsu2.png
「 👆 こいつ(状態;State)だぜ。
探索(Search) という言葉が難しければ、何かを探して状態を訪問していることだと思えだぜ」

20210618coder52a1.png

ramen-tabero-futsu2.png
「 👆 蟻本の日本語難しくて分からないんで、幅優先探索なら知ってるんで 絵にして分かりやすく説明したろ」

kifuwarabe-futsu.png
「 他の人は お父んが分かりやすいように説明されると 分からないんだけどな」

20210618coder52a1c1.png

20210618coder52a2.png

ramen-tabero-futsu2.png
「 👆 ハムスターの4方向を 右側から時計回りに光が回転して、
床のパネルは浮き上がって 筒に入っていくんだぜ」

ohkina-hiyoko-futsu.png
「 ハムスターって そんな動物だったかしら?」

20210618coder52a3.png

ramen-tabero-futsu2.png
「 👆 ハムスターを隣に移動しろだぜ。数字も増えろだぜ」

kifuwarabe-futsu.png
「 3匹になった」

20210618coder52a5.png

ramen-tabero-futsu2.png
「 👆 また、ハムスターの隣の床が光れだぜ」

20210618coder52a6.png

ramen-tabero-futsu2.png
「 👆 キューに入っていたものは捨てて、新しい床を入れろだぜ」

20210618coder52a7.png

ramen-tabero-futsu2.png
「 👆 あとは 繰り返しだな。
ハムが 移動のターン数を床に書いていってるんで、階段に着いたときには 移動の最小ターン数が分かるな」

20210618coder53.png

ramen-tabero-futsu2.png
「 👆 やっと コーディングできた。つら」

盤の入力

20210618coder54a1.png

ramen-tabero-futsu2.png
「 👆 迷路とか 土地とか、こんな感じで入力するが……」

20210618coder54a2.png

ramen-tabero-futsu2.png
「 👆 読取り方向は さきに x で、 次に y だから……」

  rep(j, N) {
    rep(i, M) { // 内側がx軸
      cin >> maze[i][j]; // (x,y)
    }
  }

ramen-tabero-futsu2.png
「 👆 二重ループの内側を x にしないといけないぜ」

ohkina-hiyoko-futsu.png
「 i, j じゃなくて x, y を使っちゃいけないの?」

ramen-tabero-futsu2.png
「 知らね」

kifuwarabe-futsu.png
「 ループカウンタは i, j, k... を使うのが習慣だが」

P39

ramen-tabero-futsu2.png
「 蟻本では DFS を 解候補の生成 と捉えてるんだな」

kifuwarabe-futsu.png
「 何だぜそれ?」

20210618coder55.png

ramen-tabero-futsu2.png
「 👆 例えば 5つの豆球があると思ってくれだぜ」

20210618coder55a1.png

ramen-tabero-futsu2.png
「 👆 電球は Off と On の2状態あるとするぜ」

20210618coder55a2.png

ramen-tabero-futsu2.png
「 👆 すると、On/Off や 並び は、いろんなパターンがあるな。
このパターンが 解候補 だぜ」

20210618coder56.png

ohkina-hiyoko-futsu.png
「 👆 枝を増やせば、 On/Off だけじゃなくて、半分点灯 とかも いけるわね」

kifuwarabe-futsu.png
「 その枝を 593 まで増やせば 将棋になるぜ」

next_permutation( )

ohkina-hiyoko-futsu.png
「 next_permutation( ) って何よ」

ramen-tabero-futsu2.png
「 さっぱり分からん。 ソースコード実装して 動かしてみよ」

ramen-tabero-futsu2.png
「 next_permutation() を使わない場合と、使う場合の2種類のソースコードがあるんだけど」

kifuwarabe-futsu.png
「 動かしてみてくれだぜ」

0 1 2 
0 2 1 
1 0 2 
1 2 0 
2 0 1 
2 1 0 

ramen-tabero-futsu2.png
「 👆 next_permutation() を使わないソースコードで、 3 を入力した結果が 上記だぜ」

ohkina-hiyoko-futsu.png
「 順列の全パターンを作ってるわねえ」

0 1 2 
0 2 1 
1 0 2 
1 2 0 
2 0 1 
2 1 0 

ramen-tabero-futsu2.png
「 👆 next_permutation() を使ったソースコードで、 3 を入力した結果が 上記だぜ」

kifuwarabe-futsu.png
「 同じじゃないか」

int perm2[3];
int n = 3;

do {
  // ここでperm2を利用
} while(next_permutation(perm2, perm2 + n))

ohkina-hiyoko-futsu.png
「 👆 next_permutation( ) の引数に何を渡しているの?」

ramen-tabero-futsu2.png
「 begin と end みたいなもんだと思うけど……」

Program:

// [コードテスト](https://atcoder.jp/contests/APG4b/custom_test)  
// C++(GCC 9.2.1)  
#include <bits/stdc++.h>
using namespace std;
#define rep(i, n) for (int i = 0; i < (int)(n); i++)

#include <algorithm>

const int N = 10;

int main() {
  int array[N] = {1, 2, 3, 4, 5, 6, 7, 8 ,9, 10};
  int begin = 3;
  int end = 6;

  do {
    // 表示
    rep(i, N) {
      cout << array[i] << " ";
    }
    cout << endl;

    // arrayの指定区間をスワップする。辞書順で現在より後ろのうち、最小のものへ
  } while (next_permutation(array + begin, array + end));
}

Output:

1 2 3 4 5 6 7 8 9 10 
1 2 3 4 6 5 7 8 9 10 
1 2 3 5 4 6 7 8 9 10 
1 2 3 5 6 4 7 8 9 10 
1 2 3 6 4 5 7 8 9 10 
1 2 3 6 5 4 7 8 9 10 

ramen-tabero-futsu2.png
「 👆 よし、分かったぜ」

kifuwarabe-futsu.png
「 教えてくれだぜ」

20210618coder57a1.png

ramen-tabero-futsu2.png
「 👆 まず 中身の入った 配列を用意しておけだぜ」

20210618coder57a2.png

ramen-tabero-futsu2.png
「 👆 次に 範囲を指定しろだぜ」

20210618coder57a3.png

ramen-tabero-futsu2.png
「 👆 next_permutation 関数は、この範囲の中の要素を スワップ(入替え)するんだぜ」

ohkina-hiyoko-futsu.png
「 勝手にスワップすんの?」

ramen-tabero-futsu2.png
「 規則性がある」

ramen-tabero-futsu2.png
「 4と5と6を使った3桁の数で、456より大きい数のうち、一番小さな数だぜ」

kifuwarabe-futsu.png
「 まわりくどい日本語wwww」

20210618coder57a4.png

ramen-tabero-futsu2.png
「 👆 ざっくり言うと、次の数だな。 465

ohkina-hiyoko-futsu.png
「 next_permutation( ) (次の順列) ねえ」

20210618coder57a5.png

ramen-tabero-futsu2.png
「 👆 もう大きくならないなら、何もスワップせず false を返すぜ。 whileループでも抜けろだぜ」

Chapter 2-2

P43

int t = min(A / V[i], C[i]); // コインiを使う枚数

ohkina-hiyoko-futsu.png
「 👆 これは何やってんの?」

20210618coder58.png

ramen-tabero-futsu2.png
「 👆 コインを持っている枚数は決まっているからな。右側は 出せるコインの枚数の最大値だぜ」

ramen-tabero-futsu2.png
「 左側は 残額を コインの額で割って 小数点切り捨て。
残額が900円なら、500円玉を2枚もっていても、ぴったり合わせるには1枚しか使えないな」

ramen-tabero-futsu2.png
「 右側のコインの枚数は、左側で3枚とか出ても、出せませんよ、という意味だぜ」

kifuwarabe-futsu.png
「 こんな min を使ったプログラム 制限時間の中で とっさに書けないぜ」

P43下

20210619coder59a1.png

ramen-tabero-futsu2.png
「 👆 この図は……」

20210619coder59a2.png

ramen-tabero-futsu2.png
「 👆 仕事が2つあるのかだぜ?」

kifuwarabe-futsu.png
「 また お父んが 勝手に解釈してら……」

20210619coder59a3.png

kifuwarabe-futsu.png
「 👆 線分1本が 仕事1つだぜ」

20210619coder59a4.png

kifuwarabe-futsu.png
「 👆 お父んが 勝手に解釈しない図にするなら、こうだな」

ramen-tabero-futsu2.png
「 なるほど……」

20210619coder59a5.png

kifuwarabe-futsu.png
「 👆 そして 仕事のスタートとエンドは 被っていることもあるぜ。
この図で選べる仕事は1つだけだな。2つは選べない」

ramen-tabero-futsu2.png
「 なるほどなるほど……」

P45

ramen-tabero-futsu2.png
「 蟻本、証明付いてないんだが」

kifuwarabe-futsu.png
「 お父んが証明しろだぜ」

ramen-tabero-futsu2.png
「 こりゃ むずかしいな……。 P43 の問題から証明しようぜ?」

20210619coder60a1.png

ramen-tabero-futsu2.png
「 👆 一番少ないブロックの数で、点線の枠を埋めろだぜ」

20210619coder60a2.png

kifuwarabe-futsu.png
「 👆 こうだぜ」

ramen-tabero-futsu2.png
「 よっしゃ!」

20210619coder60a3.png

ramen-tabero-futsu2.png
「 👆 じゃあ これでも 同じようにやってみろだぜ」

kifuwarabe-futsu.png
「 簡単だぜ。見てろだぜ」

20210619coder60a4.png

kifuwarabe-futsu.png
「 👆 こうだぜ!」

ramen-tabero-futsu2.png
「 なんで さっきより 多くブロックを使ってるんだぜ?」

kifuwarabe-futsu.png
「 水色のブロックを使ったら、緑色のブロックを使ったときより隙間が小さくなって、もう緑色のブロックが入らなくなったからだな」

ohkina-hiyoko-futsu.png
「 欲張るから そうなるのよ」

kifuwarabe-futsu.png
「 欲張っていいときと、欲張ってはダメなときの違いを教えてくれだぜ」

20210619coder61.png

ramen-tabero-futsu2.png
「 👆 それは、ブロックが小さいもの順に並んでいるときの、隣り合うブロック2つに着目しろだぜ」

20210619coder61a1.png

ramen-tabero-futsu2.png
「 👆 ぴったり収まるケースと、はみでるケースがあるだろ」

kifuwarabe-futsu.png
「 あるぜ」

ramen-tabero-futsu2.png
「 水色のブロックが緑色のブロックより大きいのは分かっているとして、
水色のブロック1つは、 緑色のブロック2つでカバーできる面積に 2 足りないわけだが……」

20210619coder61a2b1.png

ramen-tabero-futsu2.png
「 👆 この余ってるとこ」

20210619coder61a3.png

ramen-tabero-futsu2.png
「 👆 緑の左隣の小さなブロック 2つないと カバーできないだろ」

kifuwarabe-futsu.png
「 ピッタリだな」

ramen-tabero-futsu2.png
「 この はみ出たところをカバーするのに、2つかかってしまった、というのが いけない」

ohkina-hiyoko-futsu.png
「 1枚でカバーできたって、すぐには 良いとは言えないんじゃない?」

20210619coder62.png

ohkina-hiyoko-futsu.png
「 👆 ワラちゃん、黒い点線の枠を 一番少ない数のブロックで埋めなさい」

kifuwarabe-futsu.png
「 簡単だぜ。任せろだぜ」

20210619coder62a1.png

kifuwarabe-futsu.png
「 👆 でけたぜ」

ramen-tabero-futsu2.png
「 よっしゃ!」

20210619coder63.png

ramen-tabero-futsu2.png
「 👆 じゃあ 赤色のブロックが品切れのときも やってくれだぜ」

kifuwarabe-futsu.png
「 任せろだぜ」

20210619coder63a1.png

kifuwarabe-futsu.png
「 👆 これは無理だぜ」

ohkina-hiyoko-futsu.png
「 欲張るから いけないのよ」

kifuwarabe-futsu.png
「 欲張っていいときと、欲張ってはダメなときの違いを教えてくれだぜ」

20210619coder64.png

ramen-tabero-futsu2.png
「 👆 例えば 隣り合うブロックが 1つずつ違う大きさのとき……」

20210619coder64a1.png

ramen-tabero-futsu2.png
「 👆 どこでもいいんで、連続する3つのブロックを選んでくれだぜ」

20210619coder64a2.png

ramen-tabero-futsu2.png
「 👆 そして 真ん中のブロックを積み上げて、背の高い方と 比べてみてくれだぜ」

20210619coder64a3.png

ramen-tabero-futsu2.png
「 👆 その差が 背の低い方のブロック1個分なら セーフ」

ohkina-hiyoko-futsu.png
「 それだと もっと いろいろなセーフのパターンもいけそうねぇ」

kifuwarabe-futsu.png
「 そのすべてのセーフのパターンを教えてくれだぜ」

👇📖 硬貨の問題が貪欲法で解けるための条件

20210619coder65.png

ohkina-hiyoko-futsu.png
「 👆 何言ってんのか分かんないわね」

20210619coder65a1.png

ramen-tabero-futsu2.png
「 👆 nが5のときは、上図だな」

20210619coder65a2.png

ramen-tabero-futsu2.png
「 👆 a[j] は一番後ろの手前とのことだぜ」

20210619coder65a3.png

ramen-tabero-futsu2.png
「 👆 j はどこか適当に選ぶとして、 j+1 って、 j の右隣だよな。
この回りくどい言い方は、どこでも 言いハマる、と言いたいんだぜ」

kifuwarabe-futsu.png
「 数式の読み方は 一般化され過ぎていて むずかしい」

20210619coder65a4.png

ramen-tabero-futsu2.png
「 👆 δ (デルタ)は、a[j] より左の、いずれかの a だな」

ohkina-hiyoko-futsu.png
「 その 髪の毛が1本のオバQが デルタなの?」

ramen-tabero-futsu2.png
「 そうだぜ」

kifuwarabe-futsu.png
「 いずれかのa と言われたら、あいまいで 落ち着かないぜ」

ramen-tabero-futsu2.png
「 どこでもいいということは、両端の 最小のa とか、 最大のa とかにしろだぜ」

20210619coder66.png

ramen-tabero-futsu2.png
「 数式は どうとでも当てはまるから、極端なケースを入れてやれだぜ」

kifuwarabe-futsu.png
「 p は 2/3 だな」

20210619coder67.png

kifuwarabe-futsu.png
「 👆 ここまでは当てはまるが、次は どうやるんだぜ?」

20210619coder68.png

ramen-tabero-futsu2.png
「 👆 赤いブロックは十分あるとして、緑色の点線の枠を埋めろだぜ」

kifuwarabe-futsu.png
「 簡単だぜ。任せろだぜ」

20210619coder68a1.png

kifuwarabe-futsu.png
「 👆 でけたぜ」

ramen-tabero-futsu2.png
「 よっしゃ。じゃ、 H(δ) は 2 な」

20210619coder67a1.png

kifuwarabe-futsu.png
「 👆 ダメだったぜ」

ramen-tabero-futsu2.png
「 じゃあ、貪欲法 使うと解けないことがあるんだな」

kifuwarabe-futsu.png
「 必ず解ける例を 教えてくれだぜ」

20210619coder69.png

ramen-tabero-futsu2.png
「 👆 はみ出たくないんだから、こうだろ」

ohkina-hiyoko-futsu.png
「 等差数列をやめて、等比数列にしたのね」

20210619coder69a1.png

kifuwarabe-futsu.png
「 👆 適当に j を取ってみるかだぜ」

20210619coder69a2.png

kifuwarabe-futsu.png
「 👆 δ から選ぶのは 一番大きな こいつでいいだろ」

20210619coder69a3.png

kifuwarabe-futsu.png
「 👆 H(δ) は 2 だぜ」

20210619coder69a4b1.png

kifuwarabe-futsu.png
「 👆 p は 2.5 だな」

20210619coder69a5.png

kifuwarabe-futsu.png
「 👆 ダメだったぜ」

ramen-tabero-futsu2.png
「 じゃあ 引用する記事 変えようかな」

ohkina-hiyoko-futsu.png
「 2倍ぐらいの比では 足りてないんじゃないの?」

20210619coder70.png

ramen-tabero-futsu2.png
「 👆 じゃあ きふわらべ、これで」

20210619coder70a1.png

kifuwarabe-futsu.png
「 👆 適当に j を取るぜ」

20210619coder70a2.png

kifuwarabe-futsu.png
「 👆 δ から選ぶのは こいつだな」

20210619coder70a3.png

kifuwarabe-futsu.png
「 👆 H(δ) は 3 だぜ」

20210619coder70a4.png

kifuwarabe-futsu.png
「 👆 p は 3+1/3 だな」

20210619coder70a5.png

kifuwarabe-futsu.png
「 👆 ダメだったぜ」

ramen-tabero-futsu2.png
「 えっ! H(δ) が伸びてくるのかだぜ!」

ohkina-hiyoko-futsu.png
「 δの最大を取ってるから ダメなんじゃないの?」

ramen-tabero-futsu2.png
「 境界値テストをしてるんだぜ」

kifuwarabe-futsu.png
「 aは合ってるだろ。jも合ってるだろ。j+1も合ってるだろ。pも合ってるだろ。H(x)も合ってるだろ。
怪しいのは δ だぜ」

0 ≦ δ < a[j]

ramen-tabero-futsu2.png
「 👆 この記述から 何を読み取れる?」

ohkina-hiyoko-futsu.png
「 δは実数なの?」

kifuwarabe-futsu.png
「 δの取りようなんか 無限にあるのでは?」

ramen-tabero-futsu2.png
「 δは どこだぜ!」

20210619coder71.png

kifuwarabe-futsu.png
「 👆 a[j] を適当に取ろう」

20210619coder71a1.png

ohkina-hiyoko-futsu.png
「 👆 ここも δ なんじゃないの?」

ramen-tabero-futsu2.png
「 まったく その通りだぜ」

20210619coder71a2b1.png

ohkina-hiyoko-futsu.png
「 👆 δ って ここなんじゃないの?」

ramen-tabero-futsu2.png
「 まさしく δ とは 差 という意味だぜ」

kifuwarabe-futsu.png
「 じゃあ この場合 δ は  だな。
p も 2

kifuwarabe-futsu.png
「 H(δ) はどうすんのかな」

20210619coder71a4.png

kifuwarabe-futsu.png
「 👆 緑色のブロック1個を δ に埋めれるかな」

20210619coder71a3.png

kifuwarabe-futsu.png
「 👆 でけたぜ」

ramen-tabero-futsu2.png
「 つら……」

ohkina-hiyoko-futsu.png
「 で、 証明って どうやって やんの?」

20210619coder72.png

ramen-tabero-futsu2.png
「 👆 δ のとこにブロック1個埋めておわりなら 左の柱がブロック2個、右の柱がブロック2個なんで トントンだな」

ramen-tabero-futsu2.png
「 a[j] 側の同じブロックの数から1個引いたものより、
δ側をカバーするブロックの数は 同じか、より少なくあって欲しいようだな」

20210619coder72a1.png

ohkina-hiyoko-futsu.png
「 👆 気にしてるのは 2つの柱の 追加分ってことよね」

kifuwarabe-futsu.png
「 ブロックは小さな順に並んでいるというが、同じサイズのブロックが連続していてもいいのかだぜ?」

ramen-tabero-futsu2.png
「 いいのでは」

20210619coder72a2.png

ohkina-hiyoko-futsu.png
「 👆 jより1つ前のブロックではδからはみ出るけど、2つ前のブロックなら埋めれるとき、なんで いけないの?」

kifuwarabe-futsu.png
「 いけなくはないぜ。 H(δ) は、貪欲法としか指定がないんで」

ohkina-hiyoko-futsu.png
「 じゃあ いけるのか」

ramen-tabero-futsu2.png
「 図解で 面積は描けるが、 ブロックの個数であることを強調することは 視覚的な図形で 描けないしな……、
何かいい方法は無いものか」

kifuwarabe-futsu.png
「 点でいいのでは」

20210619coder72a3.png

ramen-tabero-futsu2.png
「 👆 指にしてみよ」

ohkina-hiyoko-futsu.png
「 p は自然数なの? 実数なの?」

kifuwarabe-futsu.png
「 pとδは一意に求まると 記事に説明があったが……」

20210124shogi2a2b1.png
「 どうやってだぜ?」

📖 別の記事

kifuwarabe-futsu.png
「 👆 別の記事も参照しようぜ? 右クリック利かないけど」

ramen-tabero-futsu2.png
「 どっちかのサイトが、もう片方のサイトをコピペしてるだろ。新しい発見無いぜ」

何度でもクリック!→

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位

光速のアカウント凍結されちゃったんで……。ゲームプログラムを独習中なんだぜ☆電王戦IIに出た棋士もコンピューターもみんな好きだぜ☆▲(パソコン将棋)WCSC29一次予選36位、SDT5予選42位▲(パソコン囲碁)AI竜星戦予選16位

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

むずでょ@きふわらべ第29回世界コンピューター将棋選手権一次予選36位 の最近の記事