Clasa a XII-a · Tehnici avansate: doi pointeri, căutare binară pe răspuns, stive monotoneRead in English

Generarea submulțimilor cu măști de biți în C++

În engleză: Generating subsets with bitmasks

ExponențialăC++1764 de linii1 exemplu

Ideea

O submulțime a lui {a[0], ..., a[n-1]} se poate codifica printr-un număr masca între 0 și 2^n - 1: bitul i al măștii este 1 dacă a[i] face parte din submulțime. Bitul i se testează cu (masca >> i) & 1, iar 2^n se scrie 1 << n. Parcurgând toate măștile obținem toate cele 2^n submulțimi, fără recursivitate. Programul afișează fiecare submulțime între acolade, apoi numărul submulțimilor cu suma s. Este potrivit pentru n mic (cel mult 20).

Descrierea în engleză

A subset of {a[0], ..., a[n-1]} can be encoded as a number masca between 0 and 2^n - 1: bit i of the mask is 1 if a[i] belongs to the subset. Bit i is tested with (masca >> i) & 1, and 2^n is written 1 << n. Walking through all masks gives all 2^n subsets, without recursion. The program prints every subset in braces, then the number of subsets with sum s. It suits small n (at most 20).

Complexitate
O(2^n * n)
Clasa
Clasa a XII-a (Grade 12)

Exemple

Exemplul 1

Intrare

3 12
1 5 7

Ieșire așteptată

{}
{1}
{5}
{1 5}
{7}
{1 7}
{5 7}
{1 5 7}
1

Codul C++

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

submultimi-cu-masti-de-biti.cpp
/*
 * Titlu: Generarea submulțimilor cu măști de biți
 * Clasa: 12
 * Capitol: Tehnici avansate: doi pointeri, căutare binară pe răspuns, stive monotone
 * Descriere: O submulțime a lui {a[0], ..., a[n-1]} se poate codifica printr-un
 *            număr masca între 0 și 2^n - 1: bitul i al măștii este 1 dacă a[i]
 *            face parte din submulțime. Bitul i se testează cu (masca >> i) & 1,
 *            iar 2^n se scrie 1 << n. Parcurgând toate măștile obținem toate cele
 *            2^n submulțimi, fără recursivitate. Programul afișează fiecare
 *            submulțime între acolade, apoi numărul submulțimilor cu suma s.
 *            Este potrivit pentru n mic (cel mult 20).
 * Complexitate: O(2^n * n)
 *
 * Exemplu
 * Intrare:
 * 3 12
 * 1 5 7
 * Ieșire:
 * {}
 * {1}
 * {5}
 * {1 5}
 * {7}
 * {1 7}
 * {5 7}
 * {1 5 7}
 * 1
 */
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int n;
    long long s;
    cin >> n >> s;
    vector<long long> a(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];

    int cuSumaS = 0;
    for (int masca = 0; masca < (1 << n); masca++)
    {
        long long suma = 0;
        bool primul = true;
        cout << '{';
        for (int i = 0; i < n; i++)
            if ((masca >> i) & 1)
            {
                if (!primul)
                    cout << ' ';
                cout << a[i];
                primul = false;
                suma += a[i];
            }
        cout << "}\n";
        if (suma == s)
            cuSumaS++;
    }
    cout << cuSumaS << '\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.