自然数的拆分(多种方法)

链接网址:http://tyvj.cn/Problem_Show.asp?id=1171

 
自然数拆分
 
   
  
  描述 
 输入自然数n,然后将其拆分成由若干数相加的形式,参与加法运算的数可以重复。
   
   
 输入格式 Input Format 
 输入只有一个整数n,表示待拆分的自然数n。 n<=80
   
   
  输出格式 Output Format 
 输出一个数,即所有方案数
   
   
  样例输入 
 
   
   
  样例输出 
 
   
   
  时间限制 Time Limitation 
 各个测试点1s
   
   
  注释 
 解释:
输入7,则7拆分的结果是
7=1+6
7=1+1+5
7=1+1+1+4
7=1+1+1+1+3
7=1+1+1+1+1+2
7=1+1+1+1+1+1+1
7=1+1+1+2+2
7=1+1+2+3
7=1+2+4
7=1+2+2+2
7=1+3+3
7=2+5
7=2+2+3
7=3+4


一共有14种情况,所以输出14

 

记忆式搜索

 

//  将n拆成不超过k的多个数的和
//  f(n,k)=f(n-k,k-1)+f(n,k-1)
// 记忆式搜索
#include <iostream>
#include <cstring>
using namespace std;
int a[81][81];
int f(int n,int k)
{
    if (a[n][k]!=-1) return a[n][k];//还没有算的 
    if ( n==0 ) return a[n][k]=1;//
    if ( k==0 ) return a[n][k]=0;//
    if ( n<k )  return a[n][k]=f(n,n);//
    return a[n][k]=f(n-k,k)+f(n,k-1);//n的划分含k和不含k只和 
}
int main(int argc, char *argv[])
{
    int n;
    memset(a,-1,sizeof(a));
    cin>>n;
    cout<<f(n,n)-1<<endl;
    return 0;
}


 

动态规划

#include <iostream>
#include <cstring>
using namespace std;
int dp[81][81];
int main(int argc, char *argv[])
{
    int i,k,n,s;
    while(cin>>n){ 
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;//dp[1][1]=dp[0][0]+dp[0][1]只能是dp[0][0]为1 
        for (i=1; i<=n; i++)// dp[i][k] i划分为k个数 
            for (k=1; k<=i; k++)
                dp[i][k]=dp[i-1][k-1]+dp[i-k][k];
        for (s=0,k=1; k<=n; k++)
            s=s+dp[n][k];
        cout<<s-1<<endl;
    }
    return 0;
}


母函数解法

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=10000;
int n,a[N],b[N],elem[1005];

void fun(int n)
{
    int i,j,k;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    for(i=0;i<=n;i++) a[i]=1; //先生成一个函数,实质为1+x+x^2+x^3+……x^n
    for(i=2;i<=n;i++){       //生成其余的函数对应1+x^i+x^2i+……
        for(j=0;j<=n;j++)
            for(k=0;k+j<=n;k+=i)
                b[j+k]+=a[j];
            //二多项式相乘,先将第一个多项式逐项乘后一个多项式,
            //如果二项相乘积大于x^n便可结束,道理如上一样,对最后结果无影响,
            //为什么使用k+=i*i,其实质就是一个生成函数:1+x^(i*i)+x^2(i*i)+……,
            //没有的项系数为0,对于有效的项刚累加a[j],
            //不是加1的原因为可能a[]中不存在第j项,也就是说x^j的系数为0
            for(k=0;k<=n;k++)//将结果保存在a[]中,将b[]清0,以便再循环使用
            {   a[k]=b[k];b[k]=0;}
    }        
} 

int main()
{
    scanf("%d",&n);{
        fun(n);
        int t=(a[n]-1)%2147483648;
        printf("%d\n",t);
    }
    return 0;
    
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值