最少的硬币数量组合出1到m之间的任意面值(贪心算法)

题目描述:

你有n种不同面值的硬币,每种面值的硬币都有无限多个,为了方便购物,你希望带尽量少的硬币,并且要能组合出 1 到 m 之间(包含1和m)的所有面值。

输入描述:

第一行包含两个整数:m ,n(1 ≤ n ≤ 100,1 ≤ m ≤ 109),意义如题目描述。接下来的 n 行,每行一个整数,第 i + 1 行的整数表示第 i 种硬币的面值。

输出描述:

输出一个整数,表示最少需要携带的硬币数量,再输出以空格为分隔的一串整数,表示对应的硬币面值。如果无解,则输出-1。

示例:

输入:
20 4
1

2

5

10
输出:
5

1 2 2 5 10

分析:

首先,硬币面值必须有1,否则无法组合1(其实只要有了1,便可以组合出任意面值)。

用sum表示当前能组合的最大面值,即可以组合1~sum的所有面值。

当sum ≥ m时,就停止组合。

当sum < m时,要继续组合,即组合sum + 1,我们事先把不同面值的硬币排序,从这里面找到满足 ≤ sum + 1的最大面值的硬币,为什么需要是最大面值呢,因为这样才能保证硬币数最少。假设找到的硬币面值是coin[i],此时,更新sum += a[i],并将硬币数量+1。以上面的示例为例,当sum = 4时,下一次要凑5,我们在面值数组里找到了满足条件的5,因为sum = 4表示能凑齐1~4,现在有了面值为5的硬币,又可以组合出5~9,总共可以组合出1~9,所以我们更新sum  = 4 + 5 = 9,表示现在可以组合1~9。按此思想,如此循环下去……,直到sum ≥ m。

显然是用贪心算法来解决问题了。

代码:

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<vector>
 4 using namespace std;
 5 
 6 int main()
 7 {
 8     int m = 0;            // 要组合出1~m的任意面值
 9     int n = 0;            // 不同面值的硬币数量
10     vector<int> coin;    // 不同面值的硬币
11     int sum = 0;        // 当前能组合出的最大面值
12     int count = 0;        // 当前需要的硬币数量
13     vector<int> trace;    // 当前需要的硬币面值
14     cin >> m >> n;
15     for (int i = 0; i < n; i++){
16         int temp;
17         cin >> temp;
18         coin.push_back(temp);
19     }
20     sort(coin.begin(), coin.end());    //硬币按面值升序排列
21     // 如果没有面值为1的硬币,则无解
22     if (coin[0] != 1){
23         cout << -1 << endl;
24         system("pause");
25         return 0;
26     }
27     while (true){
28         // 如果可以组合出大于等于m的面值,则输出count
29         if (sum >= m){
30             cout << count << endl;
31             for (auto &i : trace)
32                 cout << i << "\t";
33             system("pause");
34             return 0;
35         }
36         // 找满足<= sum + 1的最大面值的硬币
37         for (int i = n - 1; i >= 0; i--){
38             if (coin[i] <= sum + 1){
39                 trace.push_back(coin[i]);    // 保存需要的硬币面值
40                 sum += coin[i];                // 更新sum
41                 count++;                    // 更新count
42                 break;                        // 跳出并判断此时的sum是否>=m
43             }
44         }
45     }
46     return 0;
47 }

测试:

posted @ 2019-04-09 16:37  GarrettLu  阅读(1128)  评论(0编辑  收藏  举报