数的划分有很多种,也可以列为DP的一种模型了吧
(一)数的划分 成R份(不可空)
整数N,划分成R份,每份不可空,求方法总数
【解法】分为有1和没有1两种情况
i划分成j份的方法总数是以下两种情况之和
(1) 没有1的分法:每份取走一个1, 剩下的i-j分成j份
(2) 至少有一个1的分法:取走一份是1的,剩下的i-j分成j-1份
#include <iostream>
using namespace std;
int N, R;
int DP[1001][1001]; //DP[i][j]表示把i分成j份的方法总数
int main() {
cin >> N >> R;
for(int i=1; i<=N; i++) DP[i][1] = 1; //边界:分成一份的方法总数
for(int i=1; i<=N; i++)
for(int j=2; j<=R && j<=i; j++)
DP[i][j] = DP[i-1][j-1] + DP[i-j][j];
cout << DP[N][R] << endl;
return 0;
}
(二)数的划分 成R份(可空)
整数N,划分成R份,每份可空,求方法总数
#include <iostream>
using namespace std;
const int MAXN = 100, MAXK = 100;
int F[501][501];
int T, n, k;
int main() {
/*预处理*/
for(int i=0; i<MAXN; i ++)
for(int j=1; j<MAXK; j ++) {
if(i < 2 || j == 1) F[i][j] = 1;
else if(i < j) F[i][j] = F[i][i];
else F[i][j] = F[i][j-1] + F[i-j][j];
}
cin >> T;
while(T --) {
cin >> n >> k;
cout << F[n][k] << endl; //直接输出
}
return 0;
}
(三)数的拆分(可重复)
整数N,划分成若干正整数(每份可重复),求方法总数
完全背包问题。
#include <iostream>
using namespace std;
int N;
int DP[10001];
int main() {
cin >> N;
DP[0] = 1;
for(int i=1; i<=N; i++)
for(int j=i; j<=N; j++)
DP[j] += DP[j-i];
cout << DP[N] << endl;
return 0;
}
(四)数的拆分(不可重复)
整数N,划分成若干正整数(每份不可重复),求方法总数
01背包问题。
#include <iostream>
using namespace std;
int N;
int DP[10001];
int main() {
cin >> N;
DP[0] = 1;
for(int i=1; i<=N; i++)
for(int j=N; j>=i; j--)
DP[j] += DP[j-i];
cout << DP[N] << endl;
return 0;
}