EOJ 1027 邮资的问题

http://acm.cs.ecnu.edu.cn/problem.php?problemid=1027

题意:给N种邮票,第 i 种邮票面值为c[i], 有amt[i]张,

   问,用这些邮票,可以贴出多少面额不同的邮资。

思路:  

  一看就是须装满的多重背包(参见lrj背包九讲)。只不过问的是有多少不同面值,

  也即有多少种不同容量的背包能被装满。

  如果改成这样问:给定一个面额,有多少种贴法,那就和 poj 1837 差不多了。

  具体的:

  把每个邮票看成一个容量为c[i]的物品,dp[i][j]表示第i个物品放完后容量为j的背包的状态,

  dp[i][j] = 0:未满,dp[i][j] >= 1, 装满。

  那么:初始化:只有容量为0的在放之前已装满,故dp[i][0] = 1, i ∈ [0, n];

         其余均不能装满,初始化为0.

     状态转移:(这里顺便求了"容量为j的有几种贴法")

        for(i:1~n)

          for(k:0~amt[i])  //k次 0-1背包

            for(j:c[i]~V) //V是可能的最大值。

              dp[i][j] += dp[i-1][j-c[i]];   

        //  不知你是否注意到,这里并没有最优化问题,这里只是类dp的递推,因为结果是固定的。

  代码如下:(已1维优化)

 

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string>
 4 #include <algorithm>
 5 #include <string.h>
 6 #include <stdlib.h>
 7 #define MAX 4100
 8 using namespace std;
 9 
10 int main()
11 {
12     //freopen("testin.txt", "r", stdin);
13     //freopen("testout.txt", "w", stdout);
14     
15     int t;
16     cin >> t;
17     while(t--)
18     {
19         int n, V;
20         int c[25], amt[25];
21         cin >> n;
22         for(int i=0; i<n; i++)
23             cin >> c[i];
24         for(int i=0; i<n; i++)
25             cin >> amt[i];
26         V = MAX;  //我这里V取得比较随意,要小心。 
27         int dp[MAX+5];    
28         memset(dp, 0, sizeof(dp));
29         dp[0] = 1;
30         
31         for(int i=0; i<n; i++)
32             for(int j=1; j<=amt[i]; j++)
33                 for(int k=V; k>=c[i]; k--)
34                     dp[k] += dp[k-c[i]];
35         
36         int cnt = 0;
37         for(int i=0; i<V; i++)
38             if(dp[i])
39                 cnt ++;
40                 //cout << i << " " << dp[i] << endl;
41         cout << cnt << endl;
42     }
43     
44     
45     return 0;
46 }
View Code

 

 

 

posted on 2013-06-12 15:00  KimKyeYu  阅读(323)  评论(0编辑  收藏  举报

导航