整数划分问题(记忆化搜索和DP方法)
一、 问题 现在有一正整数N,要把它分为若干正整数之和,问有多少种本质不同的分法?
(1)其中最大数不超过m, 有多少种分法?
(2)分割后的正整数的数目不超过m个, 有多少种分法?
(3)分成最大数不超过m, 且每一个正整数都是正奇数, 有多少种分法?
(4)分成最大数不超过m, 且每一个正整数都不同,有多少种分法?
(5)分成恰好k个正整数,有多少种分法?
二、分析
(1)最大数不超过 m
(a)设dp[i][j]表示把数字 i 分成最大数不超过 j 的若干正整数之和所得的方法数
(b)有如下递推公式 ,核心是最大数m到底选还是不选

(2)分割数不超过m个
(a)设dp[i][j] 表示把数字 i 分成分割数不超过 j 的若干正整数之和所得的方法数
(b)递推公式核心:
- 到底分不分成 j 个
- 如果分成j个,则预先给每一份分 一个1,那么还剩下n-m,这n-m仍然继续分割成最多j个数;
- 如果不分成j个,那就转移到了把 i 最多分成 j-1 个数的状态
- 递推公式:

- 发现竟然和(1)完全一样!其实(1)(2)问题是完全等价的
- 从递推公式上来看,等价
- 从图形来看等价:

(3)分成最大数不超过m, 且每一个数都是正奇数
(a)设dp[i][j] 表示把数字 i 分成分割数不超过 j 的若干正奇数之和所得的方法数
(b)递推公式核心: 最大数 j 到底是不是奇数
- 如果是奇数,那么 j 是可以作为 一种分法的元素的 转态转移到到底是分出 j 还是不分出 j
- 如果不是奇数, 那么 j 是不能分出来的,状态转移到了dp[i][j-1]

(4)分成最大数不超过m, 且每一个正整数都不同
(a)设dp[i][j] 表示把数字 i 分成最大数不超过 j 的若干不同正整数之和所得的方法数
(b)递推公式核心:当前最大数选还是不选,如果选,还剩下i-j并且下次的最大数不能再是j而是j-1, 如果不选,状态转移到dp[i][j-1]

(5)分成恰好k个正整数
(a)设dp[i][j] 表示把数字 i 分成 j 个正整数之和所得的方法数
(b)递推公式核心:
- 这j个数里面含不含有1
- 若不含1,则先为每份预分配一个1,再对i-j进行分割成j份;
- 若含1,则先分出一个1, 然后再对剩下的的i-1分成 j-1份

【记忆化搜索代码】
#include<iostream>
#include<queue>
#include<list>
#include<vector>
#include<cstring>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
typedef long long ll;
const double eps=1e-;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x7fffffff;
#define MS(x,i) memset(x,i,sizeof(x))
#define rep(i,s,e) for(int i=s; i<=e; i++)
#define sc(a) scanf("%d",&a)
#define scl(a) scanf("%lld",&a)
#define sc2(a,b) scanf("%d %d", &a, &b)
#define dubug printf("debug......\n");
const int maxn = 1e2+;
int dx[] = {, , , -};
int dy[] = {, -, , }; /*
1. 把n划分成若干正整数之和 最大数不超过m 方法数
2. 把n划分成不超过m个正整数之和 方法数
1.2 等价
*/
ll dp1[maxn][maxn];
ll dp2[maxn][maxn];
ll dp3[maxn][maxn];
ll dp4[maxn][maxn]; //把n划分成不超过m的若干正整数之和 把n划分成不超过m个正整数之和 方法数
ll DP1(int n, int m){
if(dp1[n][m] != -){
return dp1[n][m];
}
ll ans = ;
if(m == || n == ){
return dp1[n][m] = ;
}
if(m == n){
return dp1[n][m] = DP1(n , m - ) + ;
}
if(m > n){
return dp1[n][m] = DP1(n,n);
}
if(m < n){
return dp1[n][m] = DP1(n-m, m) + DP1(n , m-);
}
return dp1[n][m] = ;
} //把N分成不超过m的,若干个正奇数的和 的方法数
ll DP2(int n , int m){
if(dp2[n][m] != -) return dp2[n][m]; if(n == || m == ){
return dp2[n][m] = ;
}
if(n == m){
return dp2[n][m] = DP2(n , m-) + m%;
}
if(n < m){
return dp2[n][m] = DP2(n , n);
}
if(n > m){
if(m % ){
return dp2[n][m] = DP2(n-m , m) + DP2(n , m-);
}
else{
return dp2[n][m] = DP2(n , m - );
}
}
return dp2[n][m] = ;
} //把N划分成不超过m的 不同正整数之和 的方法数
ll DP3(int n, int m){
if(dp3[n][m] != -){
return dp3[n][m];
}
if(n == ) return dp3[n][m] = ;
if(m == && n > ){
return dp3[n][m] = ;
} if(m == n){
return dp3[n][m] = DP3(n , m - ) + ;
}
if(m > n){
return dp3[n][m] = DP3(n,n);
}
if(m < n){
return dp3[n][m] = DP3(n-m, m-) + DP3(n , m-);
}
return dp3[n][m] = ;
} //把n换分成恰好k个正整数之和
ll DP4(int n, int k){
if(dp4[n][k] != -) return dp4[n][k];
if(n == && k > ) return dp4[n][k] = ;
if(k == ) return dp4[n][k] = ;
if(n == k) return dp4[n][k] = ;
if(n < k) return dp4[n][k] = ;
if(n > k) return dp4[n][k] = DP4(n-k , k) + DP4(n-, k-);
return ;
} int n,m;
int k;
int main(){
while(sc(n) != EOF){
MS(dp1, -);
MS(dp2 , -);
MS(dp3 , -);
MS(dp4 , -);
sc(k);
//printf("%lld\n", DP1(n,n));
printf("%lld\n", DP4(n,k));
// printf("%lld\n", DP1(n,k));
printf("%lld\n", DP3(n,n));
printf("%lld\n", DP2(n,n)); } return ;
}
【DP代码】
#include<iostream>
#include<queue>
#include<list>
#include<vector>
#include<cstring>
#include<set>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include<string>
#include<stdio.h>
using namespace std;
typedef long long ll;
const double eps=1e-;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const ll INF = 0x7fffffff;
#define MS(x,i) memset(x,i,sizeof(x))
#define rep(i,s,e) for(int i=s; i<=e; i++)
#define sc(a) scanf("%d",&a)
#define scl(a) scanf("%lld",&a)
#define sc2(a,b) scanf("%d %d", &a, &b)
#define dubug printf("debug......\n");
const int maxn = 1e2+;
int dx[] = {, , , -};
int dy[] = {, -, , }; int n;
int k;
ll dp1[maxn][maxn];//把n划分成若干正整数之和且最大数不超过m 方法数 或者 把n划分成不超过m个正整数之和 方法数
ll dp2[maxn][maxn];//把N分成不超过m的,若干个【正奇数】的和 的方法数
ll dp3[maxn][maxn];//把N划分成不超过m的 【不同】正整数之和的方法数
ll dp4[maxn][maxn];//把n换分成【恰好k个】正整数之和 //把n划分成若干正整数之和且最大数【不超过m】 方法数 或者 把n划分成不超过【m个】正整数之和 方法数
void DP1(){
MS(dp1, );
rep(i,,n){
rep(j,,n){
if(i == || j == ){
dp1[i][j] = ;
continue;
}
if(j < i)
dp1[i][j] = dp1[i-j][j] + dp1[i][j-];
else if(j > i)
dp1[i][j] = dp1[i][i];
else
dp1[i][j] = dp1[i][j-] + ;
}
}
} //把N分成不超过m的,若干个【正奇数】的和 的方法数
void DP2(){
MS(dp2, );
rep(i,,n){
rep(j,,n){
if(i == || j == ){
dp2[i][j] = ;
continue;
}
if(j < i){
if(j % )
dp2[i][j] = dp2[i-j][j] + dp2[i][j-];
else{
dp2[i][j] = dp2[i][j-];
}
}
else if(j == i){
dp2[i][j] = j% + dp2[i][j-];
}
else
dp2[i][j] = dp2[i][i];
}
}
} //把N划分成不超过m的 【不同】正整数之和的方法数
void DP3(){
MS(dp3, );
rep(i,,n){
rep(j,,n){
if(i == ){
dp3[i][j] = ;
continue;
}
if(j == && i > ){
dp3[i][j] = ;
continue;
}
if(i < j) dp3[i][j] = dp3[i][i];
if(i == j ){
dp3[i][j] = + dp3[i][j-];
}
if(i > j){
dp3[i][j] = dp3[i-j][j-] + dp3[i][j-];
}
}
}
// cout<<dp3[5][5]<<endl;
} //把n换分成【恰好k个】正整数之和
void DP4(){
MS(dp4 , );
rep(i, , n) {
rep(j , , n){
// if(i == 1 && j > 1) {
// dp4[i][j] = 0;
// continue;
// }
if(j == ) {
dp4[i][j] = ;
continue;
}
if(i == j) dp4[i][j] = ;
if(i > j)
dp4[i][j] = dp4[i-j][j] + dp4[i-][j-];
if(i < j)
dp4[i][j] = ;
}
}
} int main(){
while(sc(n) != EOF){
sc(k);
DP1();
DP2();
DP3();
DP4();
cout<<dp4[n][k]<<endl;
cout<<dp3[n][n]<<endl;
cout<<dp2[n][n]<<endl;
} return ;
}
- (1)(2)等价旋转图来自博客:https://blog.csdn.net/starter_____/article/details/83003200
整数划分问题(记忆化搜索和DP方法)的更多相关文章
- 记忆化搜索(DFS+DP) URAL 1223 Chernobyl’ Eagle on a Roof
题目传送门 /* 记忆化搜索(DFS+DP):dp[x][y] 表示x个蛋,在y楼扔后所需要的实验次数 ans = min (ans, max (dp[x][y-i], dp[x-1][i-1]) + ...
- 记忆化搜索(DFS+DP) URAL 1501 Sense of Beauty
题目传送门 /* 题意:给了两堆牌,每次从首部取出一张牌,按颜色分配到两个新堆,分配过程两新堆的总数差不大于1 记忆化搜索(DFS+DP):我们思考如果我们将连续的两个操作看成一个集体操作,那么这个操 ...
- hdu3555 Bomb (记忆化搜索 数位DP)
http://acm.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others) Memory ...
- POJ-1088 滑雪 (记忆化搜索,dp)
滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 86318 Accepted: 32289 Description Mich ...
- 【洛谷】3953:逛公园【反向最短路】【记忆化搜索(DP)统计方案】
P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条 ...
- HDU 2476 String painter(记忆化搜索, DP)
题目大意: 给你两个串,有一个操作! 操作时可以把某个区间(L,R) 之间的所有字符变成同一个字符.现在给你两个串A,B要求最少的步骤把A串变成B串. 题目分析: 区间DP, 假如我们直接想把A变成B ...
- hdu_3562_B-number(记忆化搜索|数位DP)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3652 题意:给你一个n,为比n小的能整除13并数字中有13的数有多少个 题解:记忆化搜索:记dp[i] ...
- BZOJ1415[Noi2005]聪聪和可可——记忆化搜索+期望dp
题目描述 输入 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行 ...
- HDU 4597 Play Game (记忆化搜索博弈DP)
题意 给出2*n个数,分两列放置,每列n个,现在alice和bob两个人依次从任意一列的对头或队尾哪一个数,alice先拿,且两个人都想拿最多,问alice最后能拿到数字总和的最大值是多少. 思路 4 ...
随机推荐
- Lazarus教程 中文版后续给出
市面上有介绍Delphi的书籍(近来Delphi的书也是越来越少了),但没有一本系统的介绍Lazarus的书,这本书是网上的仅有的一本Lazarus教程,目前全部是英文,不过我已经着手开始翻译,争取尽 ...
- 关于在虚拟机上安装iOS所遇到的问题
先配一张成功的图片: 要想实现上图所示的,就要安装 unlocker206, 安装完unlocker206 不用改里面的内容!!!看到**经验上说还要改内容,结果我试了很多次,根本不行,其实问题不在改 ...
- ehcache + spring 整合以及配置说明 ,附带整合问题 (已解决)
新做的项目,因为流量不大 就是一个征信平台,高峰流量不多,但缓存是必须的,cache到server上就可以,不需要额外的memcache.redis之类的东西. 但是遇到一个大坑,事情是这样的: 通过 ...
- ironic state information
参考: http://blog.csdn.net/zhonglinzhang/article/details/74202562 http://blog.csdn.net/wanghuiict/arti ...
- SpringBoot Rabbitmq接收消息
官网地址:https://docs.spring.io/spring-boot/docs/2.1.3.RELEASE/reference/htmlsingle/#boot-features-amqp ...
- PHP命名空间与use
当在一个大型项目很多程序员书写模板时,最怕出现的问题就是命名,如果一个PHP脚本出现了同名的类或者方法,就会报错(fatal error),使用命名空间可以 解决这个问题 知识点: 命名空间names ...
- Mysql入门的10条语句
1.查看当前服务器下面,有那些库(database)? 答: show databases; 2.如何创建一个数据库? 答 : create database 最后面在写数据库名:分号结束 3.选择数 ...
- 用canvas实现鼠标拖动绘制矩形框
需要用到jCanvas插件和jQuery. jCanvas下载:https://raw.githubusercontent.com/caleb531/jcanvas/master/jcanvas.mi ...
- [bzoj] 3224 Tyvj 1728 普通平衡树 || 平衡树板子题
#include<cstdio> #define N 100010 #define which(x) (ls[f[(x)]]==(x)) using namespace std; int ...
- BZOJ1027 [JSOI2007]合金 【计算几何 + floyd】
题目 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的 原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金的 ...