Problem Description
Given an integer num , how many different ways can it be divided into the sum of one or more integers.
For example:
num=5
All division methods are as follows:
* 5=5
* 1+4=5
* 2+3=5
* 1+1+3=5
* 1+2+2=5
* 1+1+1 +2=5
* 1+1+1+1+1=5
(note that 1+1+3=5 and 1+3+1=5 are regarded as a division method)
divide and conquer
Divide and conquer ideas
Given an integer num , the problem can be divided into several subproblems. For example, if num=5, we can first find the division method of dividing 5 into 1 number, and then find the division method of dividing 5 into 2 numbers. Finally, we can find the division method of dividing 5 into 5 numbers. Finally, adding the solutions of these sub-problems can get the answer we want.
And these sub-problems are of the same kind. The description of generalization is that given an integer num , how many division methods are there to divide it into the sum of k integers .
For this problem, we can divide it into several sub-problems.
To divide num into k integers, we first take an integer t , such that t < num , this t is the first integer we divide from num , and in the case of ensuring that the division is not repeated (how to ensure that it is not repeated in the code) Explain in detail) how many different t can be found , the solution of the original problem should be added. Then the original problem becomes the problem of how many ways to divide num-t into k-1 integers.
In this way, the solution of the problem can be obtained.
Code parsing
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <string.h>
using namespace std;
const int MAXN = 55;
int num;
stack<int> temp;
//列用栈的性质保证划分序列非递减
int solve(int num, int k) {
//返回将num分为k个数的非递减序列的分法总数
if (k == 1) return 1;
int ans = 0;
for (int i = 1; i <= num/k; i++) {
//保证划分得到的整数序列非递减
//则左边的数不大于右边的数
//i最大不能大于num/k
//否则非递减不能得到保证
if (i < temp.top()) continue;
//temp栈顶保存当前划分序列最右边(及最大)整数
//若新加入i不能保证非递减则跳过
temp.push(i);
ans += solve(num - i, k - 1);
temp.pop();
}
return ans;
}
int main(){
temp.push(0);
while (scanf("%d", &num) != EOF) {
int ans = 0;
for (int i = 1; i <= num; i++)
ans += solve(num, i);
printf("%d\n", ans);
}
return 0;
}
dynamic programming
Dynamic rules
After reading the idea of divide and conquer, the difficulty of the problem is obvious, that is, given an integer num , how many division methods are there to divide it into the sum of k integers .
- If num is divided into k integers, and there is 1 in these k integers , then divide this 1 , and the solution of the problem is the solution of dividing the integer num-1 into k-1 integers.
- If num is divided into k integers, and there is no 1 in the k integers, then after each of the k integers is decremented by 1, there are still k integers , and at this time , the division method composed of the k integers is the problem: The integer num-k divides the solution into k integers.
Using the bottom-up motion gauging strategy, the solution of the original problem is obvious after the solutions of 1. and 2. are known.
The state transition equation is as follows:
dp[i][j] = dp[i - j][j] + dp[i - 1][j - 1];
Code parsing
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <string.h>
const int MAXN = 1001;
int dp[MAXN][MAXN];
//dp[num][k] 表示将num分为k个数的划分方法数量
void dfs() {
for (int i = 1; i < MAXN; i++) {
for (int j = 2; j < i; j++) {
dp[i][j] = dp[i - j][j] + dp[i - 1][j - 1];
}
}
}
int main(){
int num, k;
memset(dp, 0, MAXN*MAXN * sizeof(int));
//初始化
for (int i = 1; i < MAXN; i++)
dp[i][1] = 1;
//将每个数划分为一个数(本身)只有一种方法
dfs();
scanf("%d%d", &num, &k);
printf("%d", dp[num][k]);
return 0;
}