Clasa a XI-a · Programare dinamicăRead in English

Numărul minim de monede în C++

În engleză: Minimum number of coins

O(n²)C++1770 de linii2 exemple

Ideea

Avem n tipuri de monede (din fiecare oricâte) și vrem să plătim exact suma S cu cât mai puține monede. Greedy-ul poate greși (pentru monedele 1, 3, 4 și S = 6 alege 4 + 1 + 1, dar 3 + 3 e mai bun). Programarea dinamică: min[s] este numărul minim de monede pentru suma s; min[0] = 0 și min[s] = 1 + min{ min[s - v] : v este o monedă, v ≤ s }. Ținem în ultima[s] moneda folosită la ultimul pas, ca să refacem plata. Se afișează numărul minim și monedele, sau „Imposibil”.

Descrierea în engleză

There are n coin types (any number of each) and we want to pay exactly the sum S with as few coins as possible. Greedy can be wrong (for the coins 1, 3, 4 and S = 6 it picks 4 + 1 + 1, but 3 + 3 is better). Dynamic programming: min[s] is the minimum number of coins for the sum s; min[0] = 0 and min[s] = 1 + min{ min[s - v] : v is a coin, v ≤ s }. In ultima[s] we keep the coin used in the last step, to rebuild the payment. The minimum number and the coins are printed, or 'Imposibil' (impossible).

Complexitate
O(n · S) timp, O(S) memorie
Clasa
Clasa a XI-a (Grade 11)

Exemple

Exemplul 1

Intrare

3 6
1 3 4

Ieșire așteptată

2
3 3
Exemplul 2

Intrare

2 7
2 4

Ieșire așteptată

Imposibil

Codul C++

Codul complet, cu comentarii în română. Îl poți modifica liber și îl poți reseta oricând.

numarul-minim-de-monede.cpp
/*
 * Titlu: Numărul minim de monede
 * Clasa: 11
 * Capitol: Programare dinamică
 * Descriere: Avem n tipuri de monede (din fiecare oricâte) și vrem să plătim exact suma S
 *            cu cât mai puține monede. Greedy-ul poate greși (pentru monedele 1, 3, 4 și
 *            S = 6 alege 4 + 1 + 1, dar 3 + 3 e mai bun). Programarea dinamică: min[s] este
 *            numărul minim de monede pentru suma s; min[0] = 0 și
 *            min[s] = 1 + min{ min[s - v] : v este o monedă, v ≤ s }. Ținem în ultima[s]
 *            moneda folosită la ultimul pas, ca să refacem plata. Se afișează numărul minim
 *            și monedele, sau „Imposibil”.
 * Complexitate: O(n · S) timp, O(S) memorie
 *
 * Exemplu
 * Intrare:
 * 3 6
 * 1 3 4
 * Ieșire:
 * 2
 * 3 3
 *
 * Exemplu
 * Intrare:
 * 2 7
 * 2 4
 * Ieșire: Imposibil
 */
#include <iostream>
using namespace std;

const int INF = 1000000000;
int v[105], minim[100005], ultima[100005];

int main()
{
    int n, S;
    cin >> n >> S;
    for (int i = 1; i <= n; i++)
    {
        cin >> v[i];
    }

    minim[0] = 0;
    for (int s = 1; s <= S; s++)
    {
        minim[s] = INF;
        for (int i = 1; i <= n; i++)
        {
            if (v[i] <= s && minim[s - v[i]] + 1 < minim[s])
            {
                minim[s] = minim[s - v[i]] + 1;
                ultima[s] = v[i];
            }
        }
    }

    if (minim[S] >= INF)
    {
        cout << "Imposibil\n";
        return 0;
    }
    cout << minim[S] << '\n';
    for (int s = S; s > 0; s -= ultima[s])
    {
        cout << ultima[s] << ' ';
    }
    cout << '\n';
    return 0;
}

Rulează pe un g++ adevărat (C++17, -O2) prin Compiler Explorer. Programele trebuie să se termine repede: există o limită de timp.