中科大-算法设计与分析-编程作业2

HOMEWORK 2 整数因子分解问题

问题描述

大于1的正整数 n 都可以分解为 n = x1 * x2 * … * xm

例如:当n=12时,共有8种不同的分解式:
12 = 12
12 = 6*2
12 = 4*3
12 = 3*4
12 = 3*2*2
12 = 2*6
12 = 2*3*2
12 = 2*2*3

算法设计 对于给定正整数n,计算n共有多少种不同的分解式。

输入格式

第一行一个正整数n (1<=n<=1000000)

输出格式

不同的分解式数目

输入样例

12

输出样例

8

算法设计思路

纯递归方法

纯递归方法的算法设计较为简单。当输入为1时,直接返回1。若输入不为1,则从2开始到n进行递归调用,每当用一个因子能整除n,计数加一。为了减少循环次数和递归调用次数,结合质数筛选定理:“n不能够被不大于根号n的任何质数整除,则n是一个质数”,将函数内的循环上限设定为 n n 。递归函数的传入值为由文件输入的正整数n,内部有一初值为1的计数变量cnt,记录n的分解式个数。函数首先判断n是否为1,若为1,则返回1;若不为1,则开始函数内从2到 n n 自增1的循环,当i能整除n时,判断i是否等于 n n ,若相等则cnt等于cnt加solve(i)的返回值,否则 cnt=cnt+solve(n/i)+solve(i) c n t = c n t + s o l v e ( n / i ) + s o l v e ( i ) 。最终函数返回cnt。代码如下:

int solve(int n) {
    if (n == 1) return 1;
        int cnt = 1;
    for (int i = 2; i <= sqrt(n); i++) {
        if (n % i == 0) {
            if (i == sqrt(n)) 
                cnt += solve(i);
            else 
                cnt += solve(n / i) + solve(i);
        }
    }
    return cnt;
}

备忘录方法

在查阅相关问题后得知,本题还可以利用动态规划中的备忘录方法求解。备忘录方法是动态规划算法的变形。与动态规划算法一样,备忘录方法用表格保存已解决的子问题的答案,在下次需要解此子问题时,只要简单地查看该子问题的解答,而不必重新计算。

此方法先定义全局int型指针num和全局int型变量length,分别保存因子的分解式个数和num数组的长度。计算方法与纯递归方法相同,不同的是在每次计算后将cnt保存到num中。代码如下:
int* num;
int length;
int lookup(int n) {
    if (n < length && num[n] != 0)  return num[n];
    int cnt = 1;
    int q = sqrt(n);
    for (int i = q; i >= 2; i--) {
        if (n % i == 0) {
            if (i == sqrt(n)) cnt += lookup(i);
            else cnt += lookup(i) + lookup(n / i);
        }
    }
    if (n < length) num[n] = cnt;
    return cnt;
}

完整代码如下

//整数因子分解问题
#include
#include
#include
#include
using namespace std;

//递归
int solve(int n) {
    if (n == 1) return 1;

    int cnt = 1;

    for (int i = 2; i <= sqrt(n); i++) {
        if (n % i == 0) {

            if (i == sqrt(n)) cnt += solve(i);
            else cnt += solve(n / i) + solve(i);
        }

    }

    return cnt;
}

int* num;
int length;

// 备忘录
int lookup(int n) {
    if (n < length && num[n] != 0) {
        return num[n];
    }

    int cnt = 1;
    int q = sqrt(n);

    for (int i = q; i >= 2; i--) {
        if (n % i == 0) {
            if (i == sqrt(n)) {
                cnt += lookup(i);
            }
            else {
                cnt += lookup(i) + lookup(n / i);
            }
        }
    }

    if (n < length) {
        num[n] = cnt;
    }
    return cnt;
}

int main()
{
    int n;
    //ifstream indata("input.txt");
    //indata >> n;
    cin >> n;
    int q = sqrt(n);
    length = q + 1;
    num = new int[length];


    memset(num, 0, length * sizeof(int));


    cout << "纯递归方法:"<//纯递归法  此方法太慢
    cout << "备忘录方法:" << lookup(n) << endl;//备忘录法  

    //ofstream outdata("output.txt");
    //outdata << solve(n);
    //outdata << lookup(n);
    //outdata.close();


    system("pause");
    return 0;
}

你可能感兴趣的:(作业)