All Euler problems
Project Euler

Counting Capacitor Circuits

Using up to 18 unit capacitors (each of capacitance 1) connected in series and/or parallel combinations, how many distinct capacitance values can be obtained? Let D(n) be the set of distinct capaci...

Source sync Apr 19, 2026
Problem #0155
Level Level 07
Solved By 4,207
Languages C++, Python
Answer 3857447
Length 358 words
number_theorycombinatoricsbrute_force

Problem Statement

This archive keeps the full statement, math, and original media on the page.

An electric circuit uses exclusively identical capacitors of the same value $C$.

The capacitors can be connected in series or in parallel to form sub-units, which can then be connected in series or in parallel with other capacitors or other sub-units to form larger sub-units, and so on up to a final circuit.

Using this simple procedure and up to $n$ identical capacitors, we can make circuits having a range of different total capacitances. For example, using up to $n=3$ capacitors of $60 \mu F$ each, we can obtain the following $7$ distinct total capacitance values:

Problem illustration

If we denote by $D(n)$ the number of distinct total capacitance values we can obtain when using up to $n$ equal-valued capacitors and the simple procedure described above, we have: $D(1)=1$, $D(2)=3$, $D(3)=7$, $\dots$

Find $D(18)$.

Reminder: When connecting capacitors $C_1, C_2$ etc in parallel, the total capacitance is $C_T = C_1 + C_2 + \cdots$,

whereas when connecting them in series, the overall capacitance is given by: $\dfrac{1}{C_T} = \dfrac{1}{C_1} + \dfrac{1}{C_2} + \cdots$

Problem 155: Counting Capacitor Circuits

Mathematical Foundation

Theorem 1 (Recursive Construction). Let D(n)D(n) be the set of distinct capacitance values achievable with exactly nn unit capacitors. Then D(1)={1}D(1) = \{1\} and for n2n \ge 2:

D(n)=k=1n/2{a+baD(k),bD(nk)}{aba+b  |  aD(k),bD(nk)}D(n) = \bigcup_{k=1}^{\lfloor n/2 \rfloor} \left\{ a + b \mid a \in D(k),\, b \in D(n-k) \right\} \cup \left\{ \frac{ab}{a+b} \;\middle|\; a \in D(k),\, b \in D(n-k) \right\}

Proof. Any circuit of n2n \ge 2 capacitors has a top-level structure that is either a parallel or series combination of two sub-circuits. If the sub-circuits use kk and nkn - k capacitors respectively (1kn11 \le k \le n - 1), then:

  • Parallel: total capacitance =a+b= a + b.
  • Series: total capacitance =11/a+1/b=aba+b= \frac{1}{1/a + 1/b} = \frac{ab}{a+b}.

Since the combination is commutative (a+b=b+aa + b = b + a and the harmonic formula is symmetric), we restrict to knkk \le n - k, i.e., kn/2k \le \lfloor n/2 \rfloor, without loss of generality. Every achievable capacitance arises from some such decomposition (by structural induction on circuits), and conversely every value produced by the formula is achievable. \square

Theorem 2 (Rationality). Every element of D(n)D(n) is a positive rational number.

Proof. By induction on nn. Base case: D(1)={1}Q>0D(1) = \{1\} \subset \mathbb{Q}_{>0}. Inductive step: if a,bQ>0a, b \in \mathbb{Q}_{>0}, then a+bQ>0a + b \in \mathbb{Q}_{>0} and ab/(a+b)Q>0ab/(a+b) \in \mathbb{Q}_{>0} (since a+b>0a + b > 0). \square

Lemma 1 (Series-Parallel Duality). If cD(n)c \in D(n), then 1/cD(n)1/c \in D(n).

Proof. By induction on circuit structure. Base: 1D(1)1 \in D(1) and 1/1=1D(1)1/1 = 1 \in D(1). Inductive step: if circuit AA achieves capacitance aa and circuit BB achieves bb, then:

  • Parallel of A,BA, B gives a+ba + b. Replacing with series gives ab/(a+b)=1/(1/a+1/b)ab/(a+b) = 1/(1/a + 1/b).
  • Series of A,BA, B gives ab/(a+b)ab/(a+b).

By the inductive hypothesis, circuits A,BA', B' achieving 1/a,1/b1/a, 1/b exist. Series of A,BA', B' gives (1/a)(1/b)1/a+1/b=1a+b\frac{(1/a)(1/b)}{1/a + 1/b} = \frac{1}{a+b}, which is 1/(a+b)1/(a+b).

Thus swapping every parallel with series and vice versa transforms cc to 1/c1/c. \square

Lemma 2 (Representation). Each capacitance is stored as a reduced fraction (p,q)(p, q) with gcd(p,q)=1\gcd(p, q) = 1 and q>0q > 0. Two capacitances are equal iff their reduced fractions are identical.

Proof. The rational numbers form a field, and the reduced-fraction representation is canonical. \square

Editorial

S(1) = {1} S(n) = union over k=1..n//2 of { a+b, a*b/(a+b) : a in S(k), b in S(n-k) } C(n) = |S(1) union … union S(n)| Uses tuples (numerator, denominator) for speed instead of Fraction. We compute cumulative union.

Pseudocode

    D = array of sets, indexed 1..N
    D[1] = {Fraction(1, 1)}

    For n from 2 to N:
        D[n] = empty set
        For k from 1 to n/2:
            For each a in D[k]:
                For each b in D[n-k]:
                    D[n].add(a + b) // parallel
                    D[n].add(a * b / (a + b)) // series

    Compute cumulative union
    all_values = D[1] union D[2] union ... union D[N]
    Return |all_values|

Complexity Analysis

  • Time: For each nn, we iterate over n/2\lfloor n/2 \rfloor splits. For each split (k,nk)(k, n-k), we compute D(k)×D(nk)|D(k)| \times |D(n-k)| combinations. Let sn=D(n)s_n = |D(n)|. The total work is n=2Nk=1n/2sksnk\sum_{n=2}^{N} \sum_{k=1}^{\lfloor n/2 \rfloor} s_k \cdot s_{n-k}. Empirically, sns_n grows to several hundred thousand for n18n \le 18, making the total work on the order of 10910^9 set insertions. Each insertion into a hash set is O(1)O(1) amortized.
  • Space: O ⁣(n=1Nsn)O\!\left(\sum_{n=1}^{N} s_n\right) to store all sets. For N=18N = 18, this is on the order of millions of fractions.

Answer

3857447\boxed{3857447}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_155/solution.cpp
#include <bits/stdc++.h>
using namespace std;

/*
 * Problem 155: Count distinct capacitance values using up to 18 unit capacitors.
 *
 * S(1) = {1}
 * S(n) = union over k=1..n/2 of { a+b, ab/(a+b) : a in S(k), b in S(n-k) }
 * C(n) = |S(1) union ... union S(n)|
 */

typedef pair<int, int> Frac; // (numerator, denominator), always reduced, den > 0

Frac make_frac(long long p, long long q) {
    if (q < 0) { p = -p; q = -q; }
    long long g = __gcd(abs(p), q);
    return {(int)(p / g), (int)(q / g)};
}

int main() {
    const int MAXN = 18;

    vector<set<Frac>> S(MAXN + 1);
    S[1].insert({1, 1});

    set<Frac> all_values;
    all_values.insert({1, 1});

    for (int n = 2; n <= MAXN; n++) {
        for (int k = 1; k * 2 <= n; k++) {
            int m = n - k;
            for (auto& a : S[k]) {
                for (auto& b : S[m]) {
                    // Parallel: a + b = (a.p*b.q + b.p*a.q) / (a.q*b.q)
                    long long pn = (long long)a.first * b.second + (long long)b.first * a.second;
                    long long pd = (long long)a.second * b.second;
                    S[n].insert(make_frac(pn, pd));

                    // Series: ab/(a+b) = (a.p*b.p) / (a.p*b.q + b.p*a.q)
                    long long sn = (long long)a.first * b.first;
                    long long sd = (long long)a.first * b.second + (long long)b.first * a.second;
                    S[n].insert(make_frac(sn, sd));
                }
            }
        }
        for (auto& f : S[n]) {
            all_values.insert(f);
        }
    }

    printf("%d\n", (int)all_values.size());
    return 0;
}