| | | | 描述 | | | 输入自然数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;
} |