説明
「ハノイの塔」は有名な古代のゲームです。質問を少し変えてみましょう。3つではなく合計4つの柱がある場合、少なくともすべてのプレートを最初の柱から4番目の柱に移動するには、プレートを何回移動する必要がありますか。
利便性をプログラミングするために、あなただけの結果が国防省出力に必要な10000値を。
フォーマット
入力フォーマット
正の整数n。(0 <n <= 50000)
出力フォーマット
n個のプレートを最初のピラーから4番目のピラーに移動するために必要な移動mod10000の最小数を表す正の整数。
例1
サンプル入力1
2
サンプル出力1
3
問題解決
- 3本の柱を設定した場合、n枚のプレートの最小移動回数はdp_3 [n]です。まず、再帰式によりdp_3 [n] = 2 * dp_3 [n-1] +1をすばやく求めることができます。
- 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。
- 問題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;
}