整数划分
来源:互联网 发布:mac install ant 编辑:程序博客网 时间:2024/05/16 17:47
题目:点击打开链接
(一)递归法
根据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,可能再次出现 m,因此是(n - m)的 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);
综合以上情况,我们可以看出,上面的结论具有递归定义特征,其中(1)和(2)属于回归条件,(3)和(4)属于特殊情况,将会转换为情况(5)。而情况(5)为通用情况,属于递推的方法,其本质主要是通过减小m以达到回归条件,从而解决问题。其递推表达式如下:
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 )
AC代码:
#include <stdio.h>int f[121][121];void init( ){ int i, j; for(i = 1; i <= 120; i++) f[i][1] = f[1][i] = 1; for(i = 2; i <= 120; i++) { for(j = 2 ; j <= 120; j++) { if(i < j) f[i][j]= f[i][i]; else if(i == j) f[i][j] = 1+ f[i][j-1]; else f[i][j] = f[i-j][j] + f[i][j-1]; } }}int main (void){ int i; init(); while(scanf("%d", &i) != EOF) printf("%d\n", f[i][i]); return 0;}
2, 母函数的方法:
http://www.cnblogs.com/hoodlum1980/archive/2008/10/11/1308493.html
这里面讲的很清楚:
#include <stdio.h>
#define MAX 120
int c1[MAX+5],c2[MAX+5];
int main()
{
int i,k,j,n;
for(i=0;i<=MAX;i++) //单位指数为1的时候
{
c1[i]=1;
c2[i]=0;
}
for(i=2;i<=MAX;i++) //单位指数分别为2`n的时候
{
for(j=0;j<=MAX;j++)//遍历前一个多项式就是前面已经相乘的多项式
for(k=0;k+j<=MAX;k+=i) //遍历下一个多项式
c2[j+k]+=c1[j]; //把结果存在C2[]中,c1[]为前i-1多项式的乘积结果;应为后一个多项式的每一项前面系数都是1,所以直接累加;
for(j=0;j<=MAX;j++)
{
c1[j]=c2[j]; //把结果赋值给c1[],便于循环
c2[j]=0;
}
}
while(scanf("%d",&n)!=EOF)
printf("%d\n",c1[n]);
return 0;
}
这个题目是最基本的,每一种数都没有限制,可以再思考一下当规定谋写数的数量的时候,情况又会是怎么样的?
#include <stdio.h>
#include <string.h>
#define maxn 125
#define Max(A,B) ( (A) > (B) ? (A) : (B) )
int dp[maxn];/*dp[i]表示整数i的分配个数*/
/*相当于一个完全背包*/
/*每一个数字就是物品.价值是数字本身,费用也是数字本身*/
void DP()
{
memset(dp,0,sizeof(dp));
dp[0] = 1 ;
for(int i = 1 ; i <= maxn ; i++)/*表示的是第i个数字*/
for(int j = i ; j <= maxn ; j++)
dp[j] += dp[j-i];
}
int main()
{
int N;
DP();
while(scanf("%d",&N) != EOF)
printf("%d\n",dp[N]);
return 0;
}
这个代码是别人写的,没有懂其中的意思,但是可以提醒我们怎么转化问题,怎么来讲具体的问题抽象出来,
转换为我们所熟知的问题和解法;
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分
- 整数划分:
- 整数划分
- 整数划分
- 整数划分
- CALayer
- 服务器端的消息分发和路由机制
- 配置eclipse+tomcat环境遇到的问题记录
- hadoop集群搭建和测试
- iOS 合并使用多个Storyboard
- 整数划分
- Python 参考手册
- IOS简单画图
- 使用HttpClient获得Ur最终跳转页面信息
- C# 利用反射调用类下的方法
- Python2 转义字符
- CSS定位学习笔记
- C语言进行二进制文件的读写操作(fopen,fwrite,fread)
- TexturePacker获得免费key 的方法