動的計画法-4-ハノイの塔

説明

「ハノイの塔」は有名な古代のゲームです。質問を少し変えてみましょう。3つではなく合計4つの柱がある場合、少なくともすべてのプレートを最初の柱から4番目の柱に移動するには、プレートを何回移動する必要がありますか。

利便性をプログラミングするために、あなただけの結果が国防省出力に必要な10000値を。

フォーマット

入力フォーマット

正の整数n。(0 <n <= 50000)

出力フォーマット

n個のプレートを最初のピラーから4番目のピラーに移動するために必要な移動mod10000の最小数を表す正の整数。

例1

サンプル入力1

2

サンプル出力1

3

問題解決

  1. 3本の柱を設定した場合、n枚のプレートの最小移動回数はdp_3 [n]です。まず、再帰式によりdp_3 [n] = 2 * dp_3 [n-1] +1をすばやく求めることができます。
  2. 4列の場合、nプレートの最小移動数はdp_4 [n]で、nプレート上のkプレートを最初に列の1つに移動でき、移動数はdp_4 [k]で、次にnkプレートを左に移動dp_3 [n-k]回移動して別の列に到達し、残りのkプレートをn-kプレートの列に移動し、dp_4 [k]回移動して、dp_4 [n] = min(2 * dp_4 [k] + dp_3 [nk])、1 <= k <i。
  3. 問題nは最大50000になる可能性があるため、明らかに直接再帰では不十分です。dp_4[]の最初の20項目を列挙し、それを解決する法則を見つけてください。

コード

最初の20項目をリストし、パターンを見つけます。

	int n;
    cin >> n;
    memset(dp_4, 0x3f, sizeof(dp_4));
    dp_3[1] = 1;
    dp_4[1] = 1;
    for (int i = 2; i <= n; i++) dp_3[i] = 2 * dp_3[i - 1] % p + 1;
    for (int i = 2; i <= n; i++) {
    
    
        for (int j = 1; j < i; j++) {
    
    
            dp_4[i] = min(dp_4[i], 2 * dp_4[j] + dp_3[i - j]);
        }
    }
    for (int i = 1; i <= n; i++) cout << dp_4[i] << " ";
    cout << endl;

演算結果:

20
1 3 5 9 13 17 25 33 41 49 65 81 97 113 129 161 193 225 257 289

ルールを見つけて、新しい繰り返しを再リストするのは非常に簡単です

#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int p = 1e4;
const int maxn = 5e4 + 2;
// int dp_3[maxn];
// int dp_4[maxn];
int dp[maxn];

int main() {
    
    
    int n;
    cin >> n;
    // memset(dp_4, 0x3f, sizeof(dp_4));
    // dp_3[1] = 1;
    // dp_4[1] = 1;
    // for (int i = 2; i <= n; i++) dp_3[i] = 2 * dp_3[i - 1] % p + 1;
    // for (int i = 2; i <= n; i++) {
    
    
    //     for (int j = 1; j < i; j++) {
    
    
    //         dp_4[i] = min(dp_4[i], 2 * dp_4[j] + dp_3[i - j]);
    //     }
    // }
    // for (int i = 1; i <= n; i++) cout << dp_4[i] << " ";
    // cout << endl;

    dp[1] = 1;
    int add = 2;  //每次增加的权值
    int cnt = 2;  //增加的次数
    for (int i = 2, j = 0; i <= n; i++) {
    
    
        dp[i] = (dp[i - 1] + add) % p;
        if (++j == cnt) {
    
    
            cnt++;
            j = 0;
            add = (add << 1) % p;
        }
    }
    // for (int i = 1; i <= n; i++) cout << dp_4[i] << " " << dp[i] << endl;
    // cout << cnt << endl;
    cout << dp[n] << endl;

    system("pause");
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_45349225/article/details/109407200