アルゴリズムの設計と分析のハーフセット問題
問題の説明
次のプロパティ(入力された自然数nを含む)を持つ数を見つける必要があります。
最初に自然数n(n <= 500)を入力し、次にこの自然数を次のように処理します。
- 何もしない
- 左側に自然数を追加しますが、自然数は元の数の半分を超えることはできません
- 番号を追加した後、自然な番号を追加できなくなるまで、このルールに従って処理を続けます
あなたが入力6、存在する場合は
6
16
26
126
36
136
出力6
問題分析
半数セットの数の繰り返し式は簡単に見つけることができます
。f(n)= 1 + ∑ i = 1 n / 2 f(i)f(n)= 1 + \ sum_ {i = 1} ^ {n / 2 } f(i)f (n )=1+i = 1∑N / 2f (i )
再帰計算を使用して再帰計算を実行します。繰り返し計算を回避するために、メモリ検索を使用します。
アルゴリズムの実装
#include <iostream>
#include <cstring>
#define N 500
using namespace std;
int a[N] = {
0}; //存储计算过的数据 初始化所有值为零
//求半数集算法
int halfSet(int);
int main()
{
int n;
cout<<"请输入n:";
cin>>n;
cout<<n<<"的半数集元素数量为:"<<halfSet(n)<<endl;
return 0;
}
int halfSet(int n){
if(a[n] > 0) return a[n];
int ret = 1;
for(int i=1;i<=n/2;i++){
ret = ret + halfSet(i);
}
a[n] = ret;
return ret;
}
ただし、上記のアルゴリズムには欠陥があり、繰り返しサブ問題が発生します。たとえば、24の半分に2つの1224があります。生成方法は異なりますが、結果は同じです。アルゴリズムを再度改善する必要があります。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <set>
using namespace std;
//求半数集算法 改进 无重复子问题
void halfSet(int,set<string>&,string);
int main()
{
int n;
set<string> s;
char *str = new char[3];
cout<<"请输入n:";
cin>>n;
if(n > 500){
cout<<"数据超范围!";
exit(0);
}
halfSet(n,s,string(itoa(n,str,10)));
cout<<n<<"的半数集元素数量为:"<<s.size()+1<<endl;
return 0;
}
void halfSet(int n,set<string> &s,string str){
char *strs = new char[3];
string mStr;
for(int i=1;i<=n/2;i++){
mStr = string(itoa(i,strs,10)) + str;
s.insert(mStr);
halfSet(i,s,mStr);
}
}
このブログの他の記事で推奨されています
アルゴリズムの設計と分析のための戦略演習を分割して征服する(パート2)