ハーフセット問題のアルゴリズム設計と分析(C ++)

問題の説明

次のプロパティ(入力された自然数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 = 1N / 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);
    }
}

このブログの他の記事で推奨されています

C ++整数配列のゼロへの自動初期化に関する記録

アルゴリズムの設計と分析のための線形時間選択

アルゴリズムの設計と分析のための戦略演習を分割して征服する(パート2)

アルゴリズムの設計と分析のための戦略演習を分割して征服する(上)

アルゴリズムの設計と分析のための戦略を分割して征服する

再帰的アルゴリズム演習のアルゴリズム設計と分析(パート2)

再帰的アルゴリズム演習のアルゴリズム設計と分析(上)

おすすめ

転載: blog.csdn.net/L333333333/article/details/102671667