1、将n划分成若干正整数之和的划分数:
设dp[i][j]为将i划分为不大于j的划分数
(1) 当i<j 时,i不能划分为大于i的数,所以dp[i][j]=dp[i][i];
(2) 当i=j 时,若划分中含有j只有一种情况,若划分中不含j相当于将i划分为不大于j-1的划分数。此时dp[i][j]=1+dp[i][j-1]。
(3) 当i>j 时,可以根据划分中是否含有j分为两种情况。若划分中含有j,划分方案数为dp[i-j][j];若划分数中不含j,相当于将i划 分为不大于j-1的划分数,为dp[i][j-1]。所以当i>j时dp[i][j]=dp[i-j][j]+dp[i][j-1];
dp[n][n]为所求。
2、将n划分成k个正整数之和的划分数:
设dp[i][j]为将i划分为j个整数的划分数。
(1) i<j为不可能出现的情况,dp[i][j]=0;
(2) 若i=j,有一种情况:i可以划分为i个1之和,dp[i][j]=1;
(3) 若i>j,可以根据划分数中是否含有1分为两类:
第一类: n 份中不包含 1 的分法,为保证每份都 >= 2,可以先拿出 k 个 1 分
到每一份,然后再把剩下的 n- k 分成 k 份即可,分法有: dp[n-k][k]
第二类: n 份中至少有一份为 1 的分法,可以先那出一个 1 作为单独的1份,剩
下的 n- 1 再分成 k- 1 份即可,分法有:dp[n-1][k-1]
dp[n][k]为所求。
3、将n划分成最大数不超过k的划分数:
通过1的方法 dp[n][k]为所求。
4、将n划分成若干个奇正整数之和的划分数:
设dp[i][j] 是将i划分成不大于j 的奇正整数的划分数。
(1)当i < j 的时候,i 不能划分成大于i的数且只能划分为奇数
如果j是奇数,dp[i][j]=dp[i][i]
如果j是偶数,dp[i][j]=dp[i][i - 1]。
(2)当i = j 的时候,若划分中含有j只有一种情况
若划分中不含j相当于将i划分为不大于j - 2的划分数
因为偶数不能取,所以是j - 2,此时dp[i][j]=1+dp[i][j - 2]。
(3)当i < j 时,可以根据划分中是否含有j分为两种情况。
若划分中含有j,相当于把i - j划分为不大于j的划分数,为dp[i-j][j];
若划分中不含j,相当于将i划分为不大于j - 2的划分数,为dp[i][j - 2]。所以dp[i][j]=dp[i-j][j]+dp[i][j-2];
dp[n][n]或者dp[n][n - 1]为所求。
5、将n划分成若干不同整数之和的划分数:
设dp[i][j]为将i划分为不超过j的不同整数的划分数。
(1) 当i<j时,i不能划分为大于i的数,所以dp[i][j]=dp[i][i];
(2) 当i=j时,若划分中含有j只有一种情况,若划分中不含j相当于将i划分为不大于j-1的划分数。此时dp[i][j]=1+dp[i][j-1]
(3) 当i>j时,可以根据划分中是否含有j分为两种情况。
若划分中含有j,则其余的划分中最大只能是j-1(与1不同的地方!!),方案数为dp[i-j][j-1];
若划分中不含j,相当于将i划分为不大于j-1的划分数,为dp[i][j-1]。所以当i>j时dp[i][j]=dp[i-j][j-1]+dp[i][j-1];
dp[n][n]为所求。
[代码1]
#include<stdio.h>
const int N=50;
const int maxn=55;
int dp1[maxn][maxn],dp2[maxn][maxn],dp3[maxn][maxn],dp4[maxn][maxn];
void init()
{
//将n划分成若干个正整数之和(将n划分成最大数不超过m)
dp1[0][0]=1;
for(int i=0; i<=N; ++i)
for(int j=1; j<=N; ++j)
{
if(j>i)
dp1[i][j]=dp1[i][i];
else
dp1[i][j]=dp1[i][j-1]+dp1[i-j][j];
}
//将n划分成m个正整数之和
dp2[0][0]=1;
for(int i=1; i<=N; ++i)
dp2[i][1]=1;
for(int i=2; i<=N; ++i)
for(int j=2; j<=i; ++j)
dp2[i][j]=dp2[i-1][j-1]+dp2[i-j][j];
//将n划分成若干奇正整数之和
for(int i=1; i<=N; ++i)
dp3[i][1]=1;
for(int i=1; i<=N; ++i)
dp3[0][i]=1;
dp3[0][0]=1;
for(int i=1; i<=N; ++i)
for(int j=2; j<=N; ++j)
{
if(j&1)
{
if(j>i)
{
if(i&1)
dp3[i][j]=dp3[i][i];
else
dp3[i][j]=dp3[i][i-1];
}
else
dp3[i][j]=dp3[i-j][j]+dp3[i][j-2];
}
else dp3[i][j]=dp3[i][j-1];
}
//将n划分成若干不同正整数之和
for(int i=1; i<=N; ++i)
{
dp4[0][i]=1;
dp4[1][i]=1;
}
for(int i=2; i<=N; ++i)
for(int j=1; j<=N; ++j)
{
if(j>i)
dp4[i][j]=dp4[i][i];
else
dp4[i][j]=dp4[i-j][j-1]+dp4[i][j-1];
}
}
int main()
{
init();
int n,k;
while(~scanf("%d%d",&n,&k))
{
printf("%d\n",dp1[n][n]);
printf("%d\n",dp2[n][k]);
printf("%d\n",dp1[n][k]);
printf("%d\n",dp3[n][n]);
printf("%d\n\n",dp4[n][n]);
}
return 0;
}
[代码2]
#include <iostream>
#include <string>
#include <cstdio>
#include <algorithm>
using namespace std;
int F(int n, int m) //分成m个数
{
if (m == 1||n==m)
return 1;
else if (n < m)
return 0;
else
return F(n - m,m) + F(n-1, m - 1);
}
int fac(int n,int m) //多干整数或不大于m的
{
if(n==1||m==1)return 1;
if(n==m)return 1+fac(n,n-1);
if(n>m) return fac(n-m,m)+fac(n,m-1);
return fac(n,n);
}
//若干个奇数
int fun (int n,int m)
{
if(m==1||n==1||m==0)return 1;
if(n<m)
{
if(n&1)return fun(n,n);
else return fun(n,n-1);
}
if(m&1)
{
if(n==m)return 1+fun(n,m-2);
if(n>m)return fun(n-m,m)+fun(n,m-2);
}
else
{
if(n==m)return 1+fun(n,m-1);
if(n>m)return fun(n-m,m)+fun(n,m-1);
}
}
int f(int n,int m) //划分成不同整数
{
if(m==1)
//我这样写实在n,m-1中在n>1的情况下m中每个方一是错的,
//因为只能有一个1
{
if(n>1)return 0;
if(n==1)return 1;
}
if(n==1)return 1;
if(n==m)return 1+f(n,n-1);
if(n>m) return f(n-m,m-1)+f(n,m-1);
return f(n,n);
}
int main()
{
int n,m;
while(cin>>n>>m)
{
cout<<fac(n,n)<<endl;
cout<<F(n,m)<<endl;
cout<<fac(n,m)<<endl;
if(n%2)
cout<<fun(n,n)<<endl;
else
cout<<fun(n,n-1)<<endl;
cout<<f(n,n)<<endl<<endl;
}
return 0;
}