Ulam Number Sequence In C++ - C++ Programming Tutorial
C++ Course / Number Theory / Ulam Number Sequence In C++

Ulam Number Sequence In C++

BLUF: Mastering Ulam Number Sequence In C++ is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: Ulam Number Sequence In C++

C++ is renowned for its efficiency. Learn how Ulam Number Sequence In C++ enables low-level control and high-performance computing in the tutorial below.

In this guide, we will explore the Ulam Number Sequence in C++ along with its functionality, pseudocode implementation, and sample illustrations.

What is the Ulam Number Sequence in C++?

In 1964, Stanislaw Ulam created a series of numbers now referred to as the Ulam numbers. The initial pair of positive integers in this numeric series is identified as U1 and U2. Subsequent numbers are generated by adding two distinct preceding terms together, following a unique single-sum expression pattern. This progression showcases the relationship between specific addition criteria and the demand for uniqueness within the sequence. Constructing such a sequence in C++ involves utilizing a hash map to keep track of sums, along with other comparable data structures, while maintaining a repository of terms. This approach ensures accurate computation while adhering to the sequence's rules, making it widely applicable in recreational math and algorithm development.

Below are the steps how the Ulam sequence works:

  • Initialization: Begin with the initial words U 1 and U 2. For instance, suppose that U 1 =1 and U 2 =2.
  • The creation of sequences: In order to calculate subsequent terms, determine the smallest integer larger than the final term that can be written in exactly one way as the sum of two different earlier terms.
  • Condition of Uniqueness: A number is not included in the sequence if it can be expressed as a sum in more than one way using previous terms.

For example, starts with U 1 =1 and U 2 =2.

The next term is U 3 =3, since 3=1+2.

The next term is U 4 =4, as 4=1+3.

The sequence continues as 1,2,3,4,6,8,….

Pseudo code:

Initialize Variables:

  • First, create a list ulamSequence and insert u 1 , u 2.
  • Create an ordered set candidates to store potential next Ulam numbers.
  • Create a hash map sumCounts to track the occurrence of sums.

Set Default Values:

  • Calculate the sum of u1 and u2
  • Assign the sum of u1 and u2 to potential values and initialize sumCounts[u1 + u2] to 1.

Generate Ulam Numbers:

  • While the size of ulamSequence is less than n:
  • Extract the smallest number from candidates as nextUlam.
  • Append nextUlam to ulamSequence.
  • Remove nextUlam from candidates.

For each number num in ulamSequence that is less than nextUlam:

  • Compute newSum=num+nextUlam.
  • Increment sumCounts[newSum] by 1.
  • If sumCounts[newSum] == 1:
  • Add newSum to candidates.
  • Else if sumCounts[newSum] > 1:
  • Remove newSum from candidates (as it violates uniqueness).
  • Return Result:
  • Return ulamSequence.
  • C++ Implementation:

Creating Ulam numbers in C++ usually entails:

  • Defining the first two terms.
  • Calculating subsequent terms repeatedly while keeping track of the sums of earlier ones.
  • Figuring out the occurrences of the sums to satisfy the uniqueness requirement.
  • Example 1:

Example

#include <iostream>
#include <vector>
#include <unordered_map>
std::vector<int> generateUlam(int n, int u1 = 1, int u2 = 2) {
    std::vector<int> ulamSequence = {u1, u2};
    std::unordered_map<int, int> sumCounts;
    for (int i = 2; i < n; ++i) {
        int nextUlam = 0;
        for (int candidate = ulamSequence.back() + 1; ; ++candidate) {
            sumCounts.clear();
            for (size_t j = 0; j < ulamSequence.size(); ++j) {
                for (size_t k = j + 1; k < ulamSequence.size(); ++k) {
                    int sum = ulamSequence[j] + ulamSequence[k];
                    if (sum > candidate) break;
                    ++sumCounts[sum];
                }
            }
            if (sumCounts[candidate] == 1) {
                nextUlam = candidate;
                break;
            }
        }
        ulamSequence.push_back(nextUlam);
    }
    return ulamSequence;
}
int main() {
    int n = 10; // Number of Ulam numbers to generate
    std::vector<int> ulam = generateUlam(n);
    std::cout << "Ulam Sequence: ";
    for (int num : ulam) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}

Output:

Output

Ulam Sequence: 1 2 3 4 6 8 11 13 16 18

Explanation:

  • The vector ulamSequence contains the initialization of the first two terms, u 1 and u 2 .
  • Uniqueness Check: Sums and the number of times they occur are tracked using an unordered map sumCounts.
  • Sequence Generation: The software iterates over potential possibilities for each new word, adding up previous terms to make sure the uniqueness condition is met.
  • Example 2: Using std::set and std:unordered _map

Example

#include <iostream>
#include <vector>
#include <set>
#include <unordered_map>

std::vector<int> generateUlamSequence(int n, int u1 = 1, int u2 = 2) {
    std::vector<int> ulamSequence = {u1, u2};
    std::set<int> candidates;
    std::unordered_map<int, int> sumCounts;

    // Initialize sums with the first two Ulam numbers
    candidates.insert(u1 + u2);
    sumCounts[u1 + u2] = 1;

    while (ulamSequence.size() < n) {
        // Find the smallest valid candidate
        int nextUlam = *candidates.begin();
        ulamSequence.push_back(nextUlam);
        candidates.erase(nextUlam);

        // Update sumCounts and candidates
        for (int num : ulamSequence) {
            if (num >= nextUlam) break;
            int newSum = num + nextUlam;

            sumCounts[newSum]++;
            if (sumCounts[newSum] == 1) {
                candidates.insert(newSum);
            } else if (sumCounts[newSum] == 2) {
                candidates.erase(newSum); // Invalid if count > 1
            }
        }
    }

    return ulamSequence;
}

int main() {
    int n = 20; // Number of Ulam numbers to generate
    std::vector<int> ulam = generateUlamSequence(n);

    std::cout << "Ulam Sequence: ";
    for (int num : ulam) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

Output:

Output

Ulam Sequence: 1 2 3 4 6 8 11 13 16 18 26 28 36 38 47 48 53 57 62 69

Conclusion:

In summary, every digit within the Ulam numerical series should be expressed as the total of two distinct previous digits in only one manner, rendering it a captivating exploration of mathematical boundaries and concepts. The origin of its computational process showcases the seamless collaboration between data structures and algorithmic reasoning. Techniques like hash maps and sorted collections guarantee both speed and accuracy. This serves as a prime illustration of preserving computational speed while handling unique scenarios in coding, particularly in C++. Apart from its theoretical fascination, exploring and forming the Ulam progression enhances problem-solving abilities and highlights the elegance of algorithmic analysis.

Input Required

This code uses input(). Please provide values below:

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience