使用母函数方法解答几个问题

由于在货币组合的题目中使用了母函数的方法,就顺便搜索一些资料和练习,加深自己的理解。

杭电ACM课件中简要介绍了母函数的方法,并给出了几道相关的题目。

1. HDU1398 Square Coins

使用指定的货币来组合一个给定的目标值,问一共有多少种可能。这道题和我们以前的货币组合题目大同小异,代码如下:

 1 #include <stdio.h>
 2 
 3 #define MAXITEMS 2048
 4 
 5 int v[17] = {0};
 6 int c1[MAXITEMS];
 7 int c2[MAXITEMS];
 8 int result[MAXITEMS];
 9 
10 void
11 MultiplePoly(int c1[], int max1, int c2[], int max2)
12 {
13     int i, j;
14     for (i = 0; i <= max1; i++) {
15         for (j = 0; j <= max2; j++) {
16             result[i + j] += c1[i] * c2[j];
17         }
18     }
19 }
20 
21 int 
22 main(int argc, char** argv)
23 {
24     int i, j;  
25     
26     for (i = 0; i < 17; i++) {
27         v[i] = (i+1)*(i+1);
28     }
29     
30     memset(c1, 0, sizeof(int) * MAXITEMS);
31     for (i = 0; i <= 300; i++) {
32         c1[i] = 1;
33     }
34     
35     for (i = 1; i < 17; i++) { 
36         memset(c2, 0, sizeof(int) * MAXITEMS);
37         for (j = 0; j <= 300; j += v[i]) {
38             c2[j] = 1;
39         }
40         memset(result, 0, sizeof(int) * MAXITEMS);
41         MultiplePoly(c1, 300, c2, 300);
42         memmove(c1, result, sizeof(int) * MAXITEMS);
43     }
44     int input;
45     while (scanf("%d", &input) == 1) {
46         if (input == EOF) {
47             break;
48         }
49         printf("%d\n", result[input]);
50     }
51     
52     return 0;
53 }
View Code

2. HDU1028 Ignatius and the Princess III

将大的数字分解成小的数字,问一共有多少种可能。和货币组合大同小异,代码如下:

 1 #include <stdio.h>
 2 
 3 #define MAXITEMS 8196
 4 
 5 int v[120] = {0};
 6 int c1[MAXITEMS];
 7 int c2[MAXITEMS];
 8 int result[MAXITEMS];
 9 
10 void
11 MultiplePoly(int c1[], int max1, int c2[], int max2)
12 {
13     int i, j;
14     for (i = 0; i <= max1; i++) {
15         for (j = 0; j <= max2; j++) {
16             result[i + j] += c1[i] * c2[j];
17         }
18     }
19 }
20 
21 int 
22 main(int argc, char** argv)
23 {
24     int i, j;  
25     
26     for (i = 0; i < 120; i++) {
27         v[i] = i+1;
28     }
29     
30     memset(c1, 0, sizeof(int) * MAXITEMS);
31     for (i = 0; i <= 120; i++) {
32         c1[i] = 1;
33     }
34     
35     for (i = 1; i < 120; i++) { 
36         memset(c2, 0, sizeof(int) * MAXITEMS);
37         for (j = 0; j <= 120; j += v[i]) {
38             c2[j] = 1;
39         }
40         memset(result, 0, sizeof(int) * MAXITEMS);
41         MultiplePoly(c1, 120, c2, 120);
42         memmove(c1, result, sizeof(int) * MAXITEMS);
43     }
44     int input;
45     while (scanf("%d", &input) != EOF) {
46         printf("%d\n", result[input]);
47     }
48     
49     return 0;
50 }
View Code

3. HDU1085 Holding Bin-Laden Captive

给定个数的1元、2元和5元,问不可能组成的最小的货币值。就是求母函数的第一个系数为0的下标。代码如下:

 1 #include <stdio.h>
 2 
 3 #define MAXITEMS 8196
 4 
 5 int v[3] = {1, 2, 5};
 6 int c1[MAXITEMS];
 7 int c2[MAXITEMS];
 8 int result[MAXITEMS];
 9 
10 void
11 MultiplePoly(int c1[], int max1, int c2[], int max2)
12 {
13     int i, j;
14     int *pResult;
15     for (i = 0; i <= max1; i++) {
16         if (c1[i] != 0) {
17             pResult = &result[0];
18             pResult += i;
19             for (j = 0; j <= max2; j++) {
20                 pResult[j] += c1[i] * c2[j];
21             }
22         }
23     }
24 }
25 
26 int 
27 main(int argc, char** argv)
28 {
29     int i, j;
30     int resultIdx;
31     int num[3] = {0, 0, 0};
32     while (scanf("%d %d %d", &num[0], &num[1], &num[2]) == 3) {
33         if (num[0] == 0 && num[1] == 0 && num[2] == 0) {
34             break;
35         }
36         memset(c1, 0, sizeof(int) * MAXITEMS);
37         for (i = 0; i <= num[0]; i++) {
38             c1[i] = 1;
39         }
40         for (i = 1; i < 3; i++) { 
41             memset(c2, 0, sizeof(int) * MAXITEMS);
42             for (j = 0; num[i] >= 0; j += v[i], num[i]--) {
43                 c2[j] = 1;
44             }
45             memset(result, 0, sizeof(int) * MAXITEMS);
46             MultiplePoly(c1, 3000, c2, 5000);
47             memmove(c1, result, sizeof(int) * MAXITEMS);
48         }
49         for (resultIdx = 0; resultIdx < MAXITEMS; resultIdx++) {
50             if (result[resultIdx] == 0) {
51                 printf("%d\n", resultIdx);
52                 break;
53             }
54         }
55     }
56     
57     return 0;
58 }
View Code

4. HDU1171 Big Event in HDU

有若干件物品,每种物品有它的价值。现在要将这些物品分配给两个机构A和B,要求分给A的不少于分给B的。等价于求母函数的系数不为零的项的中间一个项,就是给A分配的物品总价值,余下的就是给B的。代码如下(不能AC,报超时,暂时不管):

 1 #include <stdio.h>
 2 
 3 #define MAXITEMS 250000
 4 
 5 int v[50];
 6 int m[50];
 7 int c1[MAXITEMS];
 8 int c2[MAXITEMS];
 9 int result[MAXITEMS];
10 
11 void
12 MultiplePoly(int c1[], int max1, int c2[], int max2)
13 {
14     int i, j;
15     int *pResult;
16     for (i = 0; i <= max1; i++) {
17         if (c1[i] != 0) {
18             pResult = &result[0];
19             pResult += i;
20             for (j = 0; j <= max2; j++) {
21                 pResult[j] += c1[i] * c2[j];
22             }
23         }
24     }
25 }
26 
27 int 
28 main(int argc, char** argv)
29 {
30     int i, j, k;
31     int inputCnt;
32     int sum;
33     int tmp;
34     while (scanf("%d", &inputCnt) == 1)
35     {
36         if (inputCnt < 0) {
37             break;
38         }
39         memset(v, 0, sizeof(int) * 50);
40         memset(m, 0, sizeof(int) * 50);
41         /* read the v array and m array */
42         for (k = 0; k < inputCnt; k++) {
43             scanf("%d %d", &v[k], &m[k]);
44         }
45         /*printf("sum: %d\n", sum);*/
46         sum = 0;
47         /* initial first polynomial */
48         memset(c1, 0, sizeof(int) * MAXITEMS);
49         tmp = m[0];
50         sum += m[0]*v[0];
51         for (i = 0; tmp >= 0; i+=v[0], tmp--) {
52                 c1[i] = 1;
53         }
54         /* then initial others, if there is any */
55         for (i = 1; i < inputCnt; i++) { 
56             memset(c2, 0, sizeof(int) * MAXITEMS);
57             tmp = m[i];
58             sum += m[i]*v[i];
59             for (j = 0; tmp >= 0; j += v[i], tmp--) {
60                 c2[j] = 1;
61             }
62             memset(result, 0, sizeof(int) * MAXITEMS);
63             MultiplePoly(c1, sum, c2, m[i]*v[i]);
64             memmove(c1, result, sizeof(int) * MAXITEMS);
65         }
66         /* output */
67         memset(result, 0, sizeof(int) * MAXITEMS);
68         int count = 0;
69         for (i = 0; i <= sum; i++) {
70             if (c1[i] > 0) {
71                 result[count] = i;
72                 count++;
73             }
74         }
75         int partA = result[count/2];
76         int partB = sum - partA;
77         printf("%d %d\n", partA, partB);
78     }
79     return 0;
80 }
View Code

5. HDU1709 The Balance

有一架天平,给你若干个砝码,可以把砝码放在左边或者右边,能够表示出不同的克数。砝码放在左边,表示在母函数中系数为负,右边则为正。代码还没写。

 

先写到这里。

 

posted @ 2014-11-12 23:28  nipan  阅读(277)  评论(0编辑  收藏  举报