質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

Q&A

解決済

1回答

1355閲覧

動的計画法を高速化したい(メモ化の過程でメモリが足りなくなってしまう)

kuraudo

総合スコア137

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

アルゴリズム

アルゴリズムとは、定められた目的を達成するために、プログラムの理論的な動作を定義するものです。

0グッド

2クリップ

投稿2019/05/03 21:17

編集2019/05/04 01:41

背景

以下のような問題を解いているときに行き詰まりました、、

扱う文字列XYZの定義を説明すると
レベル1のときは"XYZ"であると。
レベル2のときはと言うと "X" + "XYZ" + "Y" + "XYZ" + "Z" = "XXYZYXYZZ" となる。
要するにレベルnのときに "X" + (n - 1レベ) + "Y" + (n - 1レベ) + "Z" となるような文字列。

そして、レベルxのときの特定の区間の文字列が知りたいです。
開始地点をs、終了地点をgとします。

例えば以下の入出力になる想定です。

python

1# 入力 2x = 2 3s = 3 4g = 6 5 6# 出力 7YZYX

行ったこと

登場が遅れましたが、ここで動的計画法が出てきます。
とりあえずメモ化の事を考えながらレベルxまでの文字列を生成してメモしていきました。
以下のようなコードの具合です。

python

1x, s, g = map(int, input().split()) 2dp = [""] * 52 3def create_str(level): 4 if level == 1: 5 dp[1] = "XYZ" 6 return dp[1] 7 else: 8 if dp[level] == "": 9 dp[level] = "X" + create_str(level - 1) + "Y" + create_str(level - 1) + "Z" 10 return dp[level] 11 else: 12 return dp[level] 13 14data = create_str(x) 15print(data[s-1:g])

備考

  1. 入力部分は説明と少し違いますが一行でスペース区切りで値を受け取ってる仕様で書いてます。
  2. dpの初期化で52個にしているのは制約条件でレベルの最大値が50と言う指定があるからです.

これで満足げにしていていくつかのテストケースを通してみたところ悲劇が。。。
これだと確かにほとんどのケースを通過するのですが重いテストケースの途中で実行が先に進まなくなってしまうと言う。。

考察

必要なのは求めたいレベルの-1だけであることと言うことに気がつき
必要のなくなったレベルのものを再度初期化していく事をしました。

x, s, g = map(int, input().split()) dp = [""] * 52 dp[1] = "XYZ" inDp = [False] * 52 inDp[0] = True inDp[1] = True def create_str(level): if not inDp[level]: dp[level] = "X" + create_str(level - 1) + "Y" + create_str(level - 1) + "Z" inDp[level] = True # 工夫したのはココ!! dp[level - 2] = "" return dp[level] data = create_str(x) print(data[s-1:g])

しかし、結局これくらいの工夫では結果は変わりませんでした(泣)

どなたか高速化の方法をご教示ください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

can110

2019/05/04 01:31 編集

「アルゴリズム」タグをつけるとより多くの人の目につくかと思います。 また、g-s < 100などの、sとgに何らかの制限はないでしょうか? ない場合x=30だと最大3221225469文字出力されることになりますが。
kuraudo

2019/05/04 01:42 編集

質問ありがとうございます。 ・1 ≦ s ≦ t ≦ レベル k の XYZ 文字列の長さ ・1 ≦ t - s + 1 ≦ 100 となっています。 すいません、この制約を明記できておりませんでした。 > 「アルゴリズム」タグをつけるとより多くの人の目につくかと思います。 それっぽいタグを探してたんですけど始め作った際に思い浮かばなかったのでご指摘いただけて助かりました。ありがとうございます
swordone

2019/05/04 01:53

これpaizaの問題では?
xebme

2019/05/04 04:40

動的計画法が必要でしょうか。
guest

回答1

0

ベストアンサー

文字列を結合すると大変なことになります。

文字列の長さを漸化式で表す
X(0) = 3
X(1) = 2 * X(0) + 3
X(2) = 2 * X(1) + 3

これを解くと、6 * 2 ^ n - 3

n = 100 のときとてつもなく大きくなりす。
7605903601369376408980219232253

PCで文字列の結合とスライスで解くのは無理です。

方針変更

  • 入力 x s g を受け付ける
  • x から、上の式を使って文字列の長さ L を計算する
  • ある数 n と L から L のなかで n 番目の文字を見つける関数を作る
  • s から g まで整数をインクリメントして関数を呼び、求める文字列を得る

n 番目の文字を見つける関数

  • L = 3 のとき、n 番目はすぐにわかる。
  • L > 3 の時、n が L の右端、中点、左端のとき、求める文字列はそれぞれ、'X', 'Y' ,'Z'
  • それ以外なら、n が中点より大きいか小さいかに応じて再帰
    L = (L-3)/2
    n の L に対する相対的位置を計算しなおす

これでうまくいくはず。アルゴリズムに誤りがあれば指摘してください。

投稿2019/05/04 08:08

xebme

総合スコア1081

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kuraudo

2019/05/04 10:36

貴重な回答ありがとうございます。
xebme

2019/05/04 10:50

動的計画法では、繰り返し同じ部分問題をとく必要があり、その部分問題が過去に計算したことがあるときにメモ化すると有効ですが、この問題は、毎回一度も解いたことがない部分問題を解くので、メモ化に意味がありません。動的計画法を適用できないことを認識してください。 アルゴリズムの教科書は、わずかに条件が変わると問題が解けなくなることが多いので、必ず問題分析をするよう奨めています。問題分析力を磨きましょう。
kuraudo

2019/05/04 12:05

> 問題分析力を磨きましょう。 はい、アプローチの紹介だけでなく自分の解法に対するフィードバックまでくださり大変嬉しいです。ありがとうございます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問