整数划分

时间限制:3000 ms  |  内存限制:65535 KB
难度:3
 
描述
将正整数n表示成一系列正整数之和:n=n1+n2+…+nk, 
其中n1≥n2≥…≥nk≥1,k≥1。 
正整数n的这种表示称为正整数n的划分。求正整数n的不 
同划分个数。 
例如正整数6有如下11种不同的划分: 
6; 
5+1; 
4+2,4+1+1; 
3+3,3+2+1,3+1+1+1; 
2+2+2,2+2+1+1,2+1+1+1+1; 
1+1+1+1+1+1。

 
输入
第一行是测试数据的数目M(1<=M<=10)。以下每行均包含一个整数n(1<=n<=10)。
输出
输出每组测试数据有多少种分法。
样例输入
1
6
样例输出
11
来源
[苗栋栋]原创
上传者
苗栋栋
 

此题可以用递归和动态规划两种方法来解决,首先介绍动态规划的,数组dp[N][M]表示N为被划分数,M为划分数的最大值,此题M==N,故即求dp[N][N];

1>状态转移方程:

dp[N][M]=dp[N][M-1]+dp[N-M][M];

该怎样理解呢?这里分两步:

Step 1:所划分的最大数不包括M,即每个划分数都是小于M的,此时总数为dp[N][M-1].

Step 2:所划分的最大数包括M,那么这一步被划分数就应该减去一个M,此时总数为dp[N-M][M].

到这里就是完整的思路了,应该注意的是上面的划分,划分数里有重复的数,那么如果要求划分数没有重复的呢,该怎样求呢?

这里的状态转移方程和上面就有点细微区别了.先来看看方程:

2>dp[N][M]=dp[N][M-1]+dp[N-M][M-1];

其实联系1中的步骤就不难理解了,同样分为两步:

Step 1:所划分的最大数不包括M,即每个划分数都是小于M的,此时总数也是dp[N][M-1].

Step 2:所划分的最大数包括M,那么划分就的相应的减去M,注意到不能重复,即M划分数出现的次数只能为1.所以M就得换成M-1了,即dp[N-M][M-1].

3>在拓展一下,要是划分的个数为确定的数呢?即dp[N][K].表示N被划分成K个数.

这时状态转移方程就为

dp[N][K]=dp[N-K][K]+dp[N-1][K-1].

应该这样理解:

Step 1:被划分的K个数中不包括1,那么就应该先自动的为其分配1,K个数共N-K,剩下的数自由分配,总能保证其值大于2,即dp[N-K][K].

Step 2:存在一个数为1的情况,此时剩下的N-1分给K-1个数,即dp[N-1][K-1].

代码如下:

 #include <stdio.h>
#include <string.h>
int dp[][];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int i,j,n;
memset(dp,,sizeof(dp));
scanf("%d",&n);
for(i=;i<=n;i++)
{
for(j=;j<=n;j++)
{
if(i>j)
dp[i][j]=dp[i-j][j]+dp[i][j-];
else if(i==j)
dp[i][j]=dp[i][j-]+;
else if(i<j)
dp[i][j]=dp[i][i];
}
}
printf("%d\n",dp[n][n]);
}
return ;
}

下面来介绍递归的方法:

整数划分问题是算法中的一个经典命题之一,有关这个问题的讲述在讲解到递归时基本都将涉及。所谓整数划分,是指把一个正整数n写成如下形式:

n=m1+m2+...+mi; (其中mi为正整数,并且1 <= mi <= n),则{m1,m2,...,mi}为n的一个划分。

如果{m1,m2,...,mi}中的最大值不超过m,即max(m1,m2,...,mi)<=m,则称它属于n的一个m划分。这里我们记n的m划分的个数为f(n,m);

例如当n=4时,他有5个划分,{4},{3,1},{2,2},{2,1,1},{1,1,1,1};

注意4=1+3 和 4=3+1被认为是同一个划分。

该问题是求出n的所有划分个数,即f(n, n)。下面我们考虑求f(n,m)的方法;

1.递归法:

根据n和m的关系,考虑以下几种情况:

(1)当n=1时,不论m的值为多少(m>0),只有一种划分即{1};

(2) 当m=1时,不论n的值为多少,只有一种划分即n个1,{1,1,1,...,1};

(3) 当n=m时,根据划分中是否包含n,可以分为两种情况:

(a). 划分中包含n的情况,只有一个即{n};

(b). 划分中不包含n的情况,这时划分中最大的数字也一定比n小,即n的所有(n-1)划分。

因此 f(n,n) =1 + f(n,n-1);

(4) 当n<m时,由于划分中不可能出现负数,因此就相当于f(n,n);

(5) 但n>m时,根据划分中是否包含最大值m,可以分为两种情况:

(a). 划分中包含m的情况,即{m, {x1,x2,...xi}}, 其中{x1,x2,... xi} 的和为n-m,因此这种情况下

为f(n-m,m)

(b). 划分中不包含m的情况,则划分中所有值都比m小,即n的(m-1)划分,个数为f(n,m-1);

因此 f(n, m) = f(n-m, m)+f(n,m-1);

综上所述:

f(n, m)=   1;                (n=1 or m=1)

f(n, n);                        (n<m)

1+ f(n, m-1);                (n=m)

f(n-m,m)+f(n,m-1);      (n>m)

代码如下:

 #include <stdio.h>
int f(int n,int m) // fun(n, m)表示将整数 n 划分为最大数不超过 m 的划分
{
if(n==||m==)
return ;
else if(m>n)
return f(n,n);
else if(m==n)// 此时也是两部分,如果含有 m 则只有一种只含有 m 的划分,如果不含有 m 则转化为最大数不超过 m-1 的划分
return f(n,m-)+;
else if(m<n) // 此时将问题转化为两部分 1.划分中含有 m; 2.划分中不含 m
return f(n,m-)+f(n-m,m);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
printf("%d\n",f(n,n));
}
return ;
}

最新文章

  1. 今天&lt;人人都能弹吉他&gt;免费版获得了苹果的新品推荐
  2. 【动态规划】XMU 1560 新ACM规则
  3. 玩转Win32开发(2):完整的开发流程
  4. POJ-2533最长上升子序列(DP+二分)(优化版)
  5. My97DatePicker使用的问题
  6. 软件看门狗--别让你地程序无响应(使用未公开API函数IsHungAppWindow,知识点较全)
  7. TensorFlow实现与优化深度神经网络
  8. ThreadLocal本地线程变量的理解
  9. js循环给li绑定事件实现 点击li弹出其索引值 和内容
  10. Agens层次聚类
  11. python基本语法汇总
  12. ROS 双目标定
  13. MySQL查询报错 ERROR: No query specified
  14. SpringCloud 学习(二)-1 :服务注册与发现Eureka扩展
  15. hadoop job解决大数据量关联时数据倾斜的一种办法
  16. 十一:image 图片
  17. Ubuntu12.04 修复GRUB
  18. Javascript中的函数数学运算
  19. selenium常用操作方法
  20. xshell如何让窗口并列排序

热门文章

  1. layui和jquery冲突:Syntax error, unrecognized expression: +
  2. ASP.NET 开发人员不必担心 Node 的五大理由
  3. js最高效的数组去重方法
  4. Hanoi双塔问题
  5. OpennSSL之基本了解
  6. luogu2805 [NOI2009]植物大战僵尸
  7. A Survey of Model Compression and Acceleration for Deep Neural Network时s
  8. nginx报错504
  9. iOS学习笔记17-FMDB
  10. BZOJ 2946 [Poi2000]公共串 ——后缀自动机