码迷,mamicode.com
首页 > 其他好文 > 详细

NYOJ-571 整数划分(三)

时间:2014-10-31 23:33:06      阅读:344      评论:0      收藏:0      [点我收藏+]

标签:style   blog   http   io   color   os   ar   for   sp   

此题是个非常经典的题目,这个题目包含了整数划分(一)和整数划分(二)的所有情形,而且还增加了其它的情形,主要是用递归或者说是递推式来解,只要找到了递推式剩下的任务就是找边界条件了,我觉得边界也是非常重要的一步,如果找不准边界,这个题也很难做出来,当时我就是找边界找了好长时间,边界得琢磨琢磨。递推步骤如下:

第一行:将n划分成若干正整数之和的划分数。
状态转移方程:dp[i][j]:和为i、最大数不超过j的拆分数
dp[i][j]可以分为两种情况:1、拆分项至少有一个j 2、拆分项一个j也没有
dp[i][j] = dp[i-j][[j] + dp[i][j-1]

第二行:将n划分成k个正整数之和的划分数。
dp[n-k][k]:相当于把k个1从n中拿出来,然后和n-k的拆分项相加的个数

第三行:将n划分成若干最大不超过k的正整数之和的划分数。
dp[n][k]

第四行:将n划分成若干奇正整数之和的划分数。
dp1[i][j]是当前的划分数为i,最大值为j时的中的划分数,则状态转移方程为
if(i < j && j % 2 == 1)
dp1[i][j] = dp1[i][i]
if(i < j && j % 2 == 0) (最大数不可能为偶数)
dp1[i][j] = dp1[i][i-1]
划分数中有j时的划分为dp[i][j - 2],因为它是奇数,所以要减2,
如果划分数中没有j的时候, 则它的数目可以写成dp1[i-j][j];意思就是i去掉j后,然后再划分最大为j的
dp1[i][j] = dp1[i-j][j] + dp1[i][j-2]


第五行:将n划分成若干完全不同正整数之和的划分数。
dp2[i][j]可以分两种情况:1、dp1[i][j-1]为不选择j时的方案 2、dp1[i-j][j-1]为选择j时的方案
0-1背包:dp2[i][j] = dp2[i][j-1] + dp2[i-j][j-1]

方法一(递归法):

bubuko.com,布布扣
 1 #include <stdio.h>
 2 //less_m(n, m)表示将n划分为最大是m的数 
 3 int less_m(int n, int m)
 4 {
 5     if(n == 1 || m == 1)
 6         return 1;
 7     if(n < m)
 8         return less_m(n, n);
 9     else if(n == m)
10         return 1 + less_m(n, m - 1);
11     else
12         return less_m(n, m - 1) + less_m(n - m, m);
13 }
14 //count(n, m)表示将n划分为m个数 
15 int count(int n, int m)
16 {
17     if(n < m)
18         return 0;
19     if(m == 1 || n == m)
20         return 1;
21     else
22         return count(n - 1, m - 1) + count(n - m, m);
23 }
24 //odd(n, m)表示将n划分为最大数为m的奇数之和 
25 int odd(int n, int m)
26 {
27     if(m == 1)
28         return 1;
29     if(n == 0 && m % 2 == 1)
30         return 1;
31     if(n == 0 && m == 0)
32         return 1;
33     if(n < m)
34     {
35         if(n % 2 == 0)
36             return odd(n, n - 1);
37         else
38             return odd(n, n);
39     }
40     else
41     {
42         return odd(n - m, m) + odd(n, m - 2);
43     }
44     
45 }
46 //not_duplicate(n, m)是将n划分为最大为m的数, 并且没有重复的 
47 int not_duplicate(int n, int m)
48 {
49     if(m == 0)
50         return 0;
51     if(n == 1 || n == 0)
52         return 1;
53     if(n < m)
54         return not_duplicate(n, n);
55     else
56         return not_duplicate(n, m - 1) + not_duplicate(n - m, m - 1);
57 }
58 
59 int main()
60 {
61     int n, k;
62     while(~scanf("%d %d", &n, &k))
63     {
64         printf("%d\n", less_m(n, n));
65         printf("%d\n", count(n, k));
66         printf("%d\n", less_m(n, k));
67         if(n % 2 == 1)
68             printf("%d\n", odd(n, n));
69         else
70             printf("%d\n", odd(n, n - 1));
71         printf("%d\n\n", not_duplicate(n, n));
72     }
73 
74     return 0;
75 }
View Code

方法二(递推法dp):

bubuko.com,布布扣
 1 #include <stdio.h>
 2 const int MAX = 52;
 3 int dp[MAX][MAX], dp1[MAX][MAX], dp2[MAX][MAX];    
 4 void divide()
 5 {
 6     dp[0][0] = 1;
 7     for(int i = 0; i < MAX; i++)
 8     {
 9         for(int j = 1; j < MAX; j++)
10         {
11             if(i < j)
12                 dp[i][j] = dp[i][i];
13             else
14                 dp[i][j] = dp[i][j - 1] + dp[i - j][j];
15         }
16     }
17 }
18 //这是划分奇数的函数 
19 void divide1()
20 {
21     for(int i = 1; i < MAX; i++)
22         dp1[i][1] = 1;
23     for(int i = 1; i < MAX; i += 2)
24         dp1[0][i] = 1;
25     dp1[0][0] = 1;
26     for(int i = 1; i < MAX; i++)
27     {
28         for(int j = 3; j < MAX; j += 2)
29         {
30             if(i < j)
31             {
32                 if(i % 2 == 1)
33                     dp1[i][j] = dp1[i][i];
34                 else
35                     dp1[i][j] = dp1[i][i - 1];
36             }
37             else
38                 dp1[i][j] = dp1[i][j - 2] + dp1[i - j][j];
39         }
40     }
41 }
42 //划分没有重复数字的函数 
43 void divide2()
44 {
45     for(int i = 1; i < MAX; i++)
46         dp2[0][i] = dp2[1][i] = 1;
47     for(int i = 2; i < MAX; i++)
48     {
49         for(int j = 1; j < MAX; j++)
50         {
51             if(i < j)
52                 dp2[i][j] = dp2[i][i];
53             else
54                 dp2[i][j] = dp2[i][j - 1] + dp2[i - j][j - 1];
55         }
56     }
57 }
58 
59 int main()
60 {
61     int n, k;
62     divide();
63     divide1();
64     divide2();
65     while(~scanf("%d %d", &n, &k))
66     {
67         printf("%d\n", dp[n][n]);
68         printf("%d\n", dp[n - k][k]);
69         printf("%d\n", dp[n][k]);
70         //先要判断要划分的数是否是奇数 
71         printf("%d\n", (n & 1) ? dp1[n][n] : dp1[n][n - 1]);
72         printf("%d\n\n", dp2[n][n]);
73     }
74     
75 }
View Code

 

NYOJ-571 整数划分(三)

标签:style   blog   http   io   color   os   ar   for   sp   

原文地址:http://www.cnblogs.com/Howe-Young/p/4066049.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!