热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HOJ1402:整数分解与组合优化问题研究

HOJ1402题目涉及整数划分的经典问题,旨在通过具体的实例提升对组合数学的理解和应用能力。该问题不仅考察了基本的数学原理,还要求对算法优化有深入的认识,以高效解决大规模数据下的整数分解与组合优化挑战。

HOJ1402 整数划分

http://acm.hit.edu.cn/hoj/problem/view?id=1402

【题目描述】

整数划分是一个经典的问题。希望这道题会对你的组合数学的解题能力有所帮助。

Input

每组输入是两个整数n和k。(1 <&#61; n <&#61; 50, 1 <&#61; k <&#61; n)

Output

对于每组输入&#xff0c;请输出六行。

第一行&#xff1a; 将n划分成若干正整数之和的划分数。
第二行&#xff1a; 将n划分成k个正整数之和的划分数。
第三行&#xff1a; 将n划分成最大数不超过k的划分数。
第四行&#xff1a; 将n划分成若干奇正整数之和的划分数。
第五行&#xff1a; 将n划分成若干不同整数之和的划分数。
第六行&#xff1a; 打印一个空行。

Sample Input

5 2

Sample Output

7
2
3
3
3

Hint:

  1. 将5划分成若干正整数之和的划分为&#xff1a; 5, 4&#43;1, 3&#43;2, 3&#43;1&#43;1, 2&#43;2&#43;1, 2&#43;1&#43;1&#43;1, 1&#43;1&#43;1&#43;1&#43;1
  2. 将5划分成2个正整数之和的划分为&#xff1a; 3&#43;2, 4&#43;1
  3. 将5划分成最大数不超过2的划分为&#xff1a; 1&#43;1&#43;1&#43;1&#43;1, 1&#43;1&#43;1&#43;2, 1&#43;2&#43;2
  4. 将5划分成若干奇正整数之和的划分为&#xff1a; 5, 1&#43;1&#43;3, 1&#43;1&#43;1&#43;1&#43;1
  5. 将5划分成若干不同整数之和的划分为&#xff1a; 5, 1&#43;4, 2&#43;3

 

【算法分析】

  

本题相当于5个小问题&#xff0c;首先来看最容易做的第5个小问题&#xff1a;将n划分成若干不同整数之和的划分数。则是一个典型的背包装物品问题&#xff0c;把问题转化一下&#xff0c;即一个容量为n的背包&#xff0c;重量分别为1n的物品各一个&#xff0c;求用若干物品将背包填满的方案总数。

利用动态规划的思想&#xff0c;很容易得到方程F[I,J] &#61; F[I-1,J] &#43;F[I-1,J-I]&#xff0c;其中F[I,J]表示从前I个物品中用若干个组成的总重量为J的方案总数&#xff0c;转移时要保证F[I-1,J-I]有意义。答案为F[n,n]&#xff0c;时间复杂度为O(n2)

对于前3个小问题可以归结为一个问题&#xff0c;即第2个小问题&#xff1a;把将n划分成k个正整数之和的划分数。

为了避免重复&#xff0c;我们需要按照不下降的顺序进行排列。我们形象地可以把nk份自然数划分看作n块积木堆成k列&#xff0c;那么不妨设这n块积木从左到右被堆成“阶梯状”。比如&#xff0c;下图表示的是3104份自然数划分。

 

而将该图旋转90度&#xff0c;可以很容易想出一种状态表示方法。

 

F[I,J,K]表示把J划分成I份最大为K的划分方案数&#xff0c;则有F[I,J,K] &#61; F[I-1,J-K,L]&#xff0c;其中L &#61; 1..K。时间复杂度为O&#xff08;n2k2&#xff09;。

而如果观察第一个图&#xff0c;我们还可以得到一种状态表示方式。设F[I,J]表示把I划分成J份的划分方案数&#xff0c;则有F[I,J] &#61; F[I-J,K] &#xff0c;其中K &#61; 0..J。时间复杂度为O&#xff08;nk2&#xff09;。

又由于F[I,J]&#61;F[I-J,K]&#xff08;K &#61; 0..J&#xff09;&#61;F[I-J,K]&#xff08;K &#61; 0..J-1&#xff09;&#43;F[I-J,J] &#61; F[I-1,J-1]&#43;F[I-J,J]&#xff0c;这样就把时间复杂度降为O&#xff08;nk&#xff09;。从另外一个角度想&#xff0c;我们在第一个图中“截去底边”&#xff0c;由于存在一个划分方案中含1的情况&#xff0c;我们无法确定在“截去底边”之后要把I-J分为几个数&#xff0c;那么不妨将划分方案中含1的情况单独列出来讨论&#xff0c;直接得到F[I,J] &#61; F[I-1,J-1]&#43;F[I-J,J]

对于第1个小问题的答案是∑F[N,I]&#xff08;I &#61; 1..N&#xff09;&#xff0c;第2个小问题的答案显然是F[N,K]&#xff0c;而第3个小问题的答案则是∑F[N,I]&#xff08;I &#61; 1..K&#xff09;&#xff0c;考虑上面旋转90度之后的图&#xff0c;你会发现&#xff0c;F[N,I]集合中的最高高度均为I&#xff0c;即将n划分成最大数为I的方案数。

最后来看第4个小问题&#xff0c;就是第2个小问题的分奇偶版本&#xff0c;那么设F[I,J]表示把I划分成J个奇数的划分方案数&#xff0c;G[I,J] 表示把I划分成J个偶数的划分方案数。那么还是用“截去底边”的思想&#xff0c;显然有G[I,J] &#61; F[I-J,J]。但F[I,J]却不是直接等于G[I-J,J]&#xff0c;因为这里又存在一个划分方案中含1的情况&#xff0c;同样将划分方案中含1的情况单独列出来讨论&#xff0c;则有F[I,J] &#61; G[I-J,J] &#43; F[I-1,J-1]。最后的答案就是∑F[N,I]&#xff08;I &#61; 1..N&#xff09;&#xff0c;时间复杂度为O(n2)

 

#include
#include

#include
using namespace std;const int maxn &#61; 51;int n,k;
int f[maxn][maxn], g[maxn][maxn];
int f1[maxn][maxn], f2[maxn][maxn];int main () {int i, j;int ans1, ans2, ans3, ans4, ans5;f1[0][0] &#61; 1;for (i &#61; 1; i )for (j &#61; 1; j <&#61; i; j &#43;&#43;)f1[i][j]&#61;f1[i-j][j]&#43;f1[i-1][j-1];f[0][0] &#61; g[0][0] &#61; 1;for (i &#61; 1; i )for (j &#61; 1; j <&#61; i; j &#43;&#43;){g[i][j] &#61; f[i - j][j];f[i][j] &#61; f[i - 1][j - 1] &#43; g[i - j][j];}for (i &#61; 0; i )f2[i][0] &#61; 1;for (i &#61; 1; i )for (j &#61; 1; j ){f2[i][j] &#61; f2[i - 1][j];if (j - i >&#61; 0)f2[i][j] &#43;&#61; f2[i - 1][j - i];}while (scanf ("%d %d", &n, &k) !&#61; EOF){ans1 &#61; ans2 &#61; ans3 &#61; ans4 &#61; ans5 &#61; 0;for (i &#61; 1; i <&#61; n; i &#43;&#43;)ans1 &#43;&#61; f1[n][i];ans2 &#61; f1[n][k];for (i &#61; 1; i <&#61; k; i &#43;&#43;)ans3 &#43;&#61; f1[n][i];for (i &#61; 1; i <&#61; n; i &#43;&#43;)ans4 &#43;&#61; f[n][i];ans5 &#61; f2[n][n];printf ("%d\n%d\n%d\n%d\n%d\n\n", ans1, ans2, ans3, ans4, ans5);}return 0;
}

 



推荐阅读
  • 在1995年,Simon Plouffe 发现了一种特殊的求和方法来表示某些常数。两年后,Bailey 和 Borwein 在他们的论文中发表了这一发现,这种方法被命名为 Bailey-Borwein-Plouffe (BBP) 公式。该问题要求计算圆周率 π 的第 n 个十六进制数字。 ... [详细]
  • c语言二元插值,二维线性插值c语言
    c语言二元插值,二维线性插值c语言 ... [详细]
  • 本文通过C++语言实现了一个递归算法,用于解析并计算数学表达式的值。该算法能够处理加法、减法、乘法和除法操作。 ... [详细]
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 线段树详解与实现
    本文详细介绍了线段树的基本概念及其在编程竞赛中的应用,并提供了一个具体的线段树实现代码示例。 ... [详细]
  • 二维码的实现与应用
    本文介绍了二维码的基本概念、分类及其优缺点,并详细描述了如何使用Java编程语言结合第三方库(如ZXing和qrcode.jar)来实现二维码的生成与解析。 ... [详细]
  • 本问题涉及在给定的无向图中寻找一个至少包含三个节点的环,该环上的节点不重复,并且环上所有边的长度之和最小。目标是找到并输出这个最小环的具体方案。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • Go从入门到精通系列视频之go编程语言密码学哈希算法(二) ... [详细]
  • 本文介绍如何手动实现一个字符串连接函数,该函数不依赖于C语言的标准字符串处理函数,如strcpy或strcat。函数原型为void concatenate(char *dest, char *src),其主要作用是将源字符串src追加到目标字符串dest的末尾。 ... [详细]
  • 本题要求计算一组正整数的最小公倍数(LCM)。输入包括多组测试数据,每组数据首先给出一个正整数n,随后是n个正整数。 ... [详细]
  • 本文详细介绍了如何在循环双链表的指定位置插入新元素的方法,包括必要的步骤和代码示例。 ... [详细]
  • 使用QT构建基础串口辅助工具
    本文详细介绍了如何利用QT框架创建一个简易的串口助手应用程序,包括项目的建立、界面设计与编程实现、运行测试以及最终的应用程序打包。 ... [详细]
  • 实现系统调用
    实现系统调用一、实验环境​本次操作还是基于上次编译Linux0.11内核的实验环境进行操作。环境如下:二、实验目标​通过对上述实验原理的认识,相信 ... [详细]
  • 本文探讨了如何高效地计算数组中和为2的幂的偶对数量,提供了从基础到优化的方法。 ... [详细]
author-avatar
8o断情戒爱o8
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有