2021-07-01に更新

最長増加部分列問題 (LIS) って何(^~^)!?

あわわわわわわわわ(^~^) 公開下書き

20210124shogi2a2b1.png
「 分からない問題ばかりだしな。分からなくても普通だよな」

kifuwarabe-futsu.png
「 しかし 分からない問題は出てくる」

ohkina-hiyoko-futsu.png
「 じゃあ 最長増加部分列問題(LIS; Longest Increase Subsequence)を調べましょう!」

ramen-tabero-futsu2.png
「 何だぜ、それ?」

20210701coder3.png

ohkina-hiyoko-futsu.png
「 👆 身長を測る線みたいなものを用意しましょう」

20210701coder3a1.png

ohkina-hiyoko-futsu.png
「 👆 横軸に 好きな数列を書くとしましょう」

20210701coder3a2.png

ohkina-hiyoko-futsu.png
「 👆 棒グラフを描いておくと 大きさの比較をしやすいでしょう」

20210701coder3a3.png

ohkina-hiyoko-futsu.png
「 👆 例えば 上図のように線をつなげば (1, 2, 3, 5, 8) という長さ5の数列が作れるわね」

ramen-tabero-futsu2.png
「 そういう数列で 一番長いやつを作ればいいのかだぜ?」

kifuwarabe-futsu.png
「 じゃあ まず 一番小さいやつを探そうぜ?」

20210701coder3a4.png

ramen-tabero-futsu2.png
「 👆 2つあるけど」

kifuwarabe-futsu.png
「 1番左のやつが よくないか?」

20210701coder3a5.png

ramen-tabero-futsu2.png
「 👆 じゃあ こいつで確定だな」

kifuwarabe-futsu.png
「 じゃあ次は そいつより大きいやつの中で 一番小さいやつを探そうぜ?」

20210701coder3a6.png

ramen-tabero-futsu2.png
「 👆 2だぜ」

kifuwarabe-futsu.png
「 以下同様で やってみてくれだぜ」

20210701coder3a7.png

ramen-tabero-futsu2.png
「 👆 3が 2つあるんだけど」

ohkina-hiyoko-futsu.png
「 2 より 左側は 見なくてよくない?」

20210701coder3a8.png

ramen-tabero-futsu2.png
「 👆 じゃあ 3 は こっちだな。 その左の 5と 8も 確定だろ」

kifuwarabe-futsu.png
「 アルゴリズムは 簡単に作れたな」

ohkina-hiyoko-futsu.png
「 そんな簡単なもの 問題で出してくるかなあ?」

# Longest increase subsequence

cards = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8]
subseq = []

# 1周目
minimum = 999
min_index = -1

for i in range(0, len(cards)):
    if cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(1周目) minimum={minimum} min_index={min_index}")

# 2周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(2周目) minimum={minimum} min_index={min_index}")

# 3周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(3周目) minimum={minimum} min_index={min_index}")

# 4周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(4周目) minimum={minimum} min_index={min_index}")

# 5周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(5周目) minimum={minimum} min_index={min_index}")
(1周目) minimum=1 min_index=1
(2周目) minimum=2 min_index=6
(3周目) minimum=3 min_index=9
(4周目) minimum=5 min_index=10
(5周目) minimum=8 min_index=11

ramen-tabero-futsu2.png
「 👆 決め打ちのベタ書きなら こうだけど」

ohkina-hiyoko-futsu.png
「 1周目と、2周目以降を 同じ書き方にできないの?」

# Longest increase subsequence

cards = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8]
subseq = []
min_index = 0
minimum = -1

# 1周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(1周目) minimum={minimum} min_index={min_index}")

# 2周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(2周目) minimum={minimum} min_index={min_index}")

# 3周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(3周目) minimum={minimum} min_index={min_index}")

# 4周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(4周目) minimum={minimum} min_index={min_index}")

# 5周目
pre_minimum = minimum
minimum = 999

for i in range(min_index, len(cards)):
    if pre_minimum < cards[i] and cards[i] < minimum:
        minimum = cards[i]
        min_index = i
    pass

print(f"(5周目) minimum={minimum} min_index={min_index}")

ramen-tabero-futsu2.png
「 👆 工夫して こうだな」

kifuwarabe-futsu.png
「 じゃあ 5回ループで おまとめ できるのでは?」

# Longest increase subsequence

cards = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8]
subseq = []
min_index = 0
minimum = -1

for j in range(0, 5):
    pre_minimum = minimum
    minimum = 999

    for i in range(min_index, len(cards)):
        if pre_minimum < cards[i] and cards[i] < minimum:
            minimum = cards[i]
            min_index = i
        pass

    print(f"({j}周目) minimum={minimum} min_index={min_index}")

ramen-tabero-futsu2.png
「 👆 まったく すっきり だぜ」

ohkina-hiyoko-futsu.png
「 停止条件って何なの? 5 じゃなくて、自動で判定するには」

ramen-tabero-futsu2.png
「 minimum なやつが 見つからなかったら 停止すればいいんじゃないか?」

# Longest increase subsequence

cards = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8]
subseq = []
min_index = 0
minimum = -1
count = 1

while True:
    pre_minimum = minimum
    minimum = 999

    for i in range(min_index, len(cards)):
        if pre_minimum < cards[i] and cards[i] < minimum:
            minimum = cards[i]
            min_index = i
        pass

    # 停止条件
    if minimum == 999:
        break

    print(f"({count}周目) minimum={minimum} min_index={min_index}")
    count += 1

ramen-tabero-futsu2.png
「 👆 ほい」

ohkina-hiyoko-futsu.png
「 これだと多分 二重ループだから O(n^2) なんで、 TLE になるのよ」

ramen-tabero-futsu2.png
「 どうすれば……」

何度でもクリック!→

むずでょ

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

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

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

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

ボードとは?

むずでょ の最近の記事