半数集问题

一、算法实现题:

1、问题描述:给定一个自然数n,有n开始可以一次产生半数集set(n)中的数如下:

            (1)nset(n)

            (2)n的左边加上一个自然数,但该自然数不能超过最近添加数的一半;

            (3)按此规则进行处理,直到不能在添加自然数为止。

          例:set(6) = {6,16,26,126,36,136}。半数集set(6)中有6个元素

 

2、编程任务:对于给定的自然数n,计算半数集set(n)中的元素个数。

 

3、数据输入:输入数据由文件名为input.txt的文本文件提供。每个文件只有一行,给出整数n(0<n<1000)

 

4、结果输出: 将计算结果输出到文件output.txt。输出文件只有一行,给出半数集set(n)中的元素个数。

 

二、解题思路

通过备忘录算法求解

    通过递归算法的思想可知道,在每一次求n的半数集问题,都要连续不断的求前面1n/2的子半数集问题。那么就可以为每个子问题建立一个记录项,用a[n]来保存子问题的解。在该记录项存入一个特殊的值,表示改之问题尚未求解,在求解过程中,对于每个待求的子问题,首先查看其相应的记录项。若记录项中存储的值是初始化的值,那么就表示改子问题是第一次求解。此时计算改子问题,并保存到相应的记录项中。若记录项中的值不是初始化,则表示改子问题已经被解决,记录项中的值就是改子问题的解。

 

用递归算法求解

对于一个给定的整数n,按照其半数集规则,在该数的左边只能添加小等于n/2的自然数。既在n的左边可以添加1n,2n,3n,4n,……,((n/2)-1)n,(n/2)n。那么就可以把整数n的半数集个数看成求1n/2的半数集的个数之和,然后加上1(代表整数n本身)。而(n/2)的半数集问题也可以依照上述的规律递归求出。这样就可以把一个n的问题划分为n/2个子问题。

set(n)为求n的半数集函数,那么n的半数集个数=set(1)+set(2)+……+set((n/2)-1)+set(n/2)

三、算法描述 

//方法一 备忘录

#include <stdio.h>

int a[1000],b;  // a[1000]做为子问题的备忘录。

void get(int n)

{   int i,j,k;

     for(i=b+1; i <= n; i++)

{   k = i/2;

         for(a[i]=j=1; j <= k; j++)

            a[i] = a[i] + a[j];

 }

 b = n;

}

void main()

{   int n;

    b = a[0] = a[1] = 1;

 while(scanf("%d",&n)!=EOF)

{     if(n > b)// 当所提供的整数小于备忘录中所存的数,

//就直接求解

         get(n);

         printf("the result is %d/n",a[n]);

 }

}

 

//方法二 递归算法

#include <fstream.h>

#include <iostream.h>

ifstream fin("input.txt");

ofstream fout("output.txt");

int set(int m)

{   int i;

    unsigned long count=1;

    for(i=1;i <=m/2;i++)

    {

        count+=set(i);

    }

    return count;

}

void main()//  主函数

{    int n;

fin >> n;

fout<<set(n)<<endl;

fin.close();

fout.close();

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值