因式分解(搜索剪枝)

因式分解
总时间限制: 100ms 内存限制: 65536kB
描述
将大于1的自然数N进行因式分解,满足 N=a1*a2*……*am 编一个程序,对任意的自然数N,求N的
所有形式不同的因式分解方案总数。
例如,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
输入
第1行:1个正整数N(N<=2*10^9)
输出
第1行:一个整数,表示N的因式分解方案总数
样例输入

12

样例输出

8

提示
预处理

首先,很多人看到这道题,就毫不犹豫——爆搜~,废话不多说,上爆搜代码!

#include<cstdio>
int ans;
void dfs(int x)
{
    if(x==1) //边界条件
    {
        ans++;
    }
    else
    {
        for(int i=2;i<=x;i++) 
            if(x%i==0) //如果找到因子
                dfs(x/i);//继续递归找下一个因子
    }
}
int main()
{
    int n;
    scanf("%d",&n); //输入n
    dfs(n);//搜索因子
    printf("%d",ans); //输出总方案数
    return 0;
}

通俗易懂吗^_^,但是,显然这样会超时,现在,我们就要预处理一下,首先要明确:
一个数的因子的因子一定是它的因子,就拿样例走走:
12的因子:
2,3,4,6,12
因子的因子的个数
1,1,2,2,1
奇怪,1+1+2+2+1就等于8,我告诉你,这就是本题的方法,就这样预处理
上代码

#include<cstdio>
#include<cmath>
int cnt,a[1000005],f[1000005];
//预处理,缩小搜索范围,可以大大节约时间
void chuli(int x)
{
    for(int i=2;i<=sqrt(x);i++) //枚举出每个因子(包括完全平方数)
    {
        if(x%i==0)
        {
            a[++cnt]=i;
        }
    }
    int j=cnt;
    cnt*=2;
    if(a[j]*a[j]==x) cnt--; //处理完全平方数
    for(int i=1;i<=j;i++)//打印下一半因子
    {
        a[cnt-i+1]=x/a[i];
    }
    a[++cnt]=x;
    /*for(int i=1;i<=cnt;i++)
        printf("%d ",a[i]);*/
}
int dfs(int k)
{
    if(f[k]>0) //边界
    {
        return f[k];
    }
    if(k==0) //边界
    {
        return f[k]=0;
    }
    int t;
    for(int i=k;i>=1;i--)
    {
        if(a[k]%a[i]==0) //搜索因子的因子的数量并累加
        {
            if(a[k]==a[i])
            {
                f[k]++;
            }
            else
            {
                t=a[k]/a[i];//如果没搜完,就继续搜
                int j=k-1;
                while(a[j]!=t)
                {
                    j--;
                }
                f[k]+=dfs(j);
            }
        }
    }
    return f[k];
}
int main()
{
    int n;
    scanf("%d",&n);
    chuli(n);//先预处理,然后算出拆分的总方法数
    int ans=dfs(cnt);
    printf("%d",ans);
    return 0;
}

相信细心的读者也发现:k==0这个边界条件可以不要,因为k根本就不可能变成0
所以,可以去掉这个边界条件,也是对的

#include<cstdio>
#include<cmath>
int cnt,a[1000005],f[1000005];
//预处理,缩小搜索范围,可以大大节约时间
void chuli(int x)
{
    for(int i=2;i<=sqrt(x);i++) //枚举出每个因子(包括完全平方数)
    {
        if(x%i==0)
        {
            a[++cnt]=i;
        }
    }
    int j=cnt;
    cnt*=2;
    if(a[j]*a[j]==x) cnt--; //处理完全平方数
    for(int i=1;i<=j;i++)//打印下一半因子
    {
        a[cnt-i+1]=x/a[i];
    }
    a[++cnt]=x;
    /*for(int i=1;i<=cnt;i++)
        printf("%d ",a[i]);*/
}
int dfs(int k)
{
    if(f[k]>0) //边界
    {
        return f[k];
    }
    /*if(k==0) //边界
    {
        return f[k]=0;
    }*/ //这个边界可要可不要
    int t;
    for(int i=k;i>=1;i--)
    {
        if(a[k]%a[i]==0) //搜索因子的因子的数量并累加
        {
            if(a[k]==a[i])
            {
                f[k]++;
            }
            else
            {
                t=a[k]/a[i];//如果没搜完,就继续搜
                int j=k-1;
                while(a[j]!=t)
                {
                    j--;
                }
                f[k]+=dfs(j);
            }
        }
    }
    return f[k];
}
int main()
{
    int n;
    scanf("%d",&n);
    chuli(n);//先预处理,然后算出拆分的总方法数
    int ans=dfs(cnt);
    printf("%d",ans);
    return 0;
}

现在比较一下,爆搜的运行想、时间会超过5分钟,非常恐怖,而搜索剪枝后,运行时间为3毫秒,这差距!!!!,所以,深搜一般会伴随着剪枝,才会防止超时,注意哦~

猜你喜欢

转载自blog.csdn.net/qq_42995099/article/details/81812597