一、 问题 现在有一正整数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 ;
}

整数划分问题(记忆化搜索和DP方法)的更多相关文章

  1. 记忆化搜索(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]) + ...

  2. 记忆化搜索(DFS+DP) URAL 1501 Sense of Beauty

    题目传送门 /* 题意:给了两堆牌,每次从首部取出一张牌,按颜色分配到两个新堆,分配过程两新堆的总数差不大于1 记忆化搜索(DFS+DP):我们思考如果我们将连续的两个操作看成一个集体操作,那么这个操 ...

  3. hdu3555 Bomb (记忆化搜索 数位DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=3555 Bomb Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  4. POJ-1088 滑雪 (记忆化搜索,dp)

    滑雪 Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 86318 Accepted: 32289 Description Mich ...

  5. 【洛谷】3953:逛公园【反向最短路】【记忆化搜索(DP)统计方案】

    P3953 逛公园 题目描述 策策同学特别喜欢逛公园.公园可以看成一张N个点M条边构成的有向图,且没有 自环和重边.其中1号点是公园的入口,N号点是公园的出口,每条边有一个非负权值, 代表策策经过这条 ...

  6. HDU 2476 String painter(记忆化搜索, DP)

    题目大意: 给你两个串,有一个操作! 操作时可以把某个区间(L,R) 之间的所有字符变成同一个字符.现在给你两个串A,B要求最少的步骤把A串变成B串. 题目分析: 区间DP, 假如我们直接想把A变成B ...

  7. hdu_3562_B-number(记忆化搜索|数位DP)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=3652 题意:给你一个n,为比n小的能整除13并数字中有13的数有多少个 题解:记忆化搜索:记dp[i] ...

  8. BZOJ1415[Noi2005]聪聪和可可——记忆化搜索+期望dp

    题目描述 输入 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行 ...

  9. HDU 4597 Play Game (记忆化搜索博弈DP)

    题意 给出2*n个数,分两列放置,每列n个,现在alice和bob两个人依次从任意一列的对头或队尾哪一个数,alice先拿,且两个人都想拿最多,问alice最后能拿到数字总和的最大值是多少. 思路 4 ...

随机推荐

  1. 《算法》C++代码 快速排序

    快速排序,简称快排,常称QuickSort.QSort.在排序算法中非常常用,其编程复杂度低,时间复杂度O(NlogN),空间复杂度O(N),执行效率稳定,而且常数很低. 基本思想就是二分,例如你要将 ...

  2. Jmeter获取Cookie并传递到下一个线程---跨线程后cookie找不到了

    网上找了一堆文章没有一个是实际操作的,自己边试边查边摸索终于找到了一个全套的办法. 原创文章,转载请说明出处. 1.取得cookie 直接这样写就可以了${COOKIE_JSESSIONID},当然具 ...

  3. centos7系列问题

    一.CentOS7.1查看ip route有两条路由规则 1.metric值是指到达目的地需要的跳数,是表达该条路由连接质量的指标.当有多条到达相同目的地的路由记录时,路由器会采用metric值小的那 ...

  4. Unresolved defparam reference to 'read_aclr_synch' in dcfifo_component.read_aclr_synch

    问题: 今天用 questasim 仿真出现下面这个问题. Unresolved defparam reference to 'read_aclr_synch' in dcfifo_component ...

  5. Nginx下配置codeigniter框架

    原来在winserver+Apache环境下工作良好的一个微信公众号后台迁移到阿里云(环境:Ubuntu 64位 | PHP5.4 | Nginx1.6)下却频出 404,403,只能访问CI rou ...

  6. [CF954G]Castle Defense

    题目大意:有$n$个点,每个点最开始有$a_i$个弓箭手,在第$i$个位置的弓箭手可以给$[i-r,i+r]$区间加上$1$的防御,你还有$k$个弓箭手,要求你最大化最小防御值 题解:二分答案,从右向 ...

  7. url为什么要编码及php中的中文字符urlencode基本原理

    首先了解以下中文字符在使用urlencode的时候运用的基本原理: urlencode()函数原理就是首先把中文字符转换为十六进制,然后在每个字符前面加一个标识符%. 此字符串中除了 -_. 之外的所 ...

  8. Codeforces Round #356 (Div. 2) C

    C. Bear and Prime 100 time limit per test 1 second memory limit per test 256 megabytes input standar ...

  9. Sed替换文本中的指定内容

    可以这样做:方法1:sed -i 's/被替换的内容/要替换成的内容/' file 方法2:sed 's/被替换的内容/要替换成的内容/g' file > file.outmv file.out ...

  10. ztree 2.0 节点搜索

    最近做了一个简单的功能,树节点的搜索.ztree的版本的2.0,3.X以上的版本请百度解决办法. 1.在setting中增加 function getFontCss(treeId, treeNode) ...