标签:组合 lin ring init res ret data turn lap
一、这个专题有什么用
练练DP
练练组合数学
......
二、正题
此类问题有如下几种形态:
1. 将n划分成若干正整数之和的划分数。
2. 将n划分成k个正整数之和的划分数。
3. 将n划分成最大数不超过k的划分数。
4. 将n划分成若干奇正整数之和的划分数。
5. 将n划分成若干不同整数之和的划分数。
1:将n划分成若干正整数的划分数
(1):划分数可以存在相同的数
那么,设dp[n][m]表示整数 n 的划分中,每个数不大于 m 的划分数。
则划分数可以分为两种情况:
a.划分中每个数都小于 m,相当于每个数不大于 m- 1, 故划分数为 dp[n][m-1]
b.划分中有一个数为 m. 那就在 n中减去 m ,剩下的就相当于把 n-m 进行划分, 故划分数为 dp[n-m][m]
总递推式:dp[n][m]=dp[n][m-1]+dp[n-m][m]
(2):划分数不可以存在相同的数
若还是设成同样的状态,从(1)可以看出,a条件是不会改变的,而b条件中,n-m后由于不存在重复,则划分数变为dp[n-m][m-1]
总递推式:dp[n][m]=dp[n][m-1]+dp[n-m][m-1]
2:将n划分成k个正整数的划分数
设dp[i][k]为,把i分成k分的划分法
那么也有两种情况:
a.n份中不包括1的情况,那么每份中都可以拿出1来,即为dp[i-k][k]
b.n份中起码有1个1的情况,那么把这个1去掉,变为dp[i-1][k-1]
总递推式:dp[i][k]=dp[i-k][k]+dp[i-1][k-1]
3:将n划分成若干奇数的划分数
设g[i][j]:将i划分成j个偶数
f[i][j]:将i划分成j个奇数
对于偶数来讲,为f[i-j][j]中的共j个数,每个加1,则变成偶数。
对于奇数来讲,为g[i-j][j]中的共j个数,每个加1,则变成奇数;且还有新加入的1,则为f[i-1][j-1]
所以递推式为:g[i][j]=f[i-j][j] , f[i][j]=f[i-1][j-1]
可以看一看HitOJ1402的代码:
1 /* 2 * hit1402.c 3 * 4 * Created on: 2011-10-11 5 * Author: bjfuwangzhu 6 */ 7 8 #include<stdio.h> 9 #include<string.h> 10 #define nmax 51 11 int num[nmax][nmax]; //将i划分为不大于j的个数 12 int num1[nmax][nmax]; //将i划分为不大于j的不同的数 13 int num2[nmax][nmax]; //将i划分为j个数 14 int f[nmax][nmax]; //将i划分为j个奇数 15 int g[nmax][nmax]; //将i划分为j个偶数 16 void init() { 17 int i, j; 18 for (i = 0; i < nmax; i++) { 19 num[i][0] = 0, num[0][i] = 0, num1[i][0] = 0, num1[0][i] = 0, num2[i][0] = 20 0, num2[0][i] = 0; 21 } 22 for (i = 1; i < nmax; i++) { 23 for (j = 1; j < nmax; j++) { 24 if (i < j) { 25 num[i][j] = num[i][i]; 26 num1[i][j] = num1[i][i]; 27 num2[i][j] = 0; 28 } else if (i == j) { 29 num[i][j] = num[i][j - 1] + 1; 30 num1[i][j] = num1[i][j - 1] + 1; 31 num2[i][j] = 1; 32 33 } else { 34 num[i][j] = num[i][j - 1] + num[i - j][j]; 35 num1[i][j] = num1[i][j - 1] + num1[i - j][j - 1]; 36 num2[i][j] = num2[i - 1][j - 1] + num2[i - j][j]; 37 } 38 } 39 } 40 f[0][0] = 1, g[0][0] = 1; 41 for (i = 1; i < nmax; i++) { 42 for (j = 1; j <= i; j++) { 43 g[i][j] = f[i - j][j]; 44 f[i][j] = f[i - 1][j - 1] + g[i - j][j]; 45 } 46 } 47 } 48 int main() { 49 #ifndef ONLINE_JUDGE 50 freopen("data.in", "r", stdin); 51 #endif 52 int n, k, i, res0, res1, res2, res3, res4; 53 init(); 54 while (~scanf("%d %d", &n, &k)) { 55 res0 = num[n][n]; 56 res1 = num2[n][k]; 57 res2 = num[n][k]; 58 for (i = 0, res3 = 0; i <= n; i++) { 59 res3 += f[n][i]; 60 } 61 res4 = num1[n][n]; 62 printf("%d\n%d\n%d\n%d\n%d\n\n", res0, res1, res2, res3, res4); 63 } 64 return 0; 65 }
未完待续............
标签:组合 lin ring init res ret data turn lap
原文地址:http://www.cnblogs.com/ibilllee/p/7655317.html