整数划分问题(记忆化搜索和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 ...
随机推荐
- Object Pascal中文手册 经典教程
Object Pascal 参考手册 (Ver 0.1)ezdelphi@hotmail.com OverviewOverview(概述)Using object pascal(使用 object p ...
- python利用PIL库使图片高斯模糊
一.安装PIL PIL是Python Imaging Library简称,用于处理图片.PIL中已经有图片高斯模糊处理类,但有个bug(目前最新的1.1.7bug还存在),就是模糊半径写死的是2,不能 ...
- 【Python】python模块加载
一个python文件就是一个模块 标准模块 python自带的模块就是标准模块,也就说可以直接import进来的就是标准模块 import datetime import random 第三方模块 别 ...
- Oracle 监听/数据库 启动/关闭
LSNRCTL命令启动.关闭和查看监听器的状态的方法 从lsnrctl status命令的输出中得到监听器状态,包括如下的信息: 监听器的启动时间 监听器的运行时间 监听器参数文件listener.o ...
- A Neural Algorithm of Artistic Style
本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/53931536 1. 资源 Paper: ...
- Nagios 监控系统架设全攻略
Nagios 全名为(Nagios Ain’t Goona Insist on Saintood),最初项目名字是 NetSaint.它是一款免费的开源 IT 基础设施监控系统,其功能强大,灵活性强, ...
- C#如何在keydown事件里判断按下的是左shift还是右shift
public partial class Form1 : Form { [System.Runtime.InteropServices.DllImport("user32.dll" ...
- IO多路复用的理解
最近看了<后台开发核心技术与应用实践>有关select.poll和epoll部分以及相关的一些博客,学习了这三个函数的使用方法和区别,写一个易理解的总结. IO多路复用 之前程序中使用的I ...
- hdu 2616 Kill the monster (DFS)
Kill the monster Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- Codeforces 846D Monitor(简单二分+二维BIT)
D. Monitor time limit per test 2 seconds memory limit per test 256 megabytes input standard input ou ...