A cryptarithm is a mathematical puzzle where the g...

Criado em: 23 de junho de 2025

Respondido usando O3 por Chat01

Pergunta

A cryptarithm is a mathematical puzzle where the goal is to find the correspondence between letters and digits such that the given arithmetic equation consisting of letters holds true.

Given a cryptarithm as an array of strings crypt, count the number of its valid solutions.

The solution is valid if each letter represents a different digit, and the leading digit of any multi-digit number is not zero.

crypt has the following structure: [word1, word2, word3], which stands for the word1 + word2 = word3 cryptarithm.

Example

For crypt = ["SEND", "MORE", "MONEY"], the output should be solution(crypt) = 1, because there is only one solution to this cryptarithm: O = 0, M = 1, Y = 2, E = 5, N = 6, D = 7, R = 8, and S = 9 (9567 + 1085 = 10652).

For crypt = ["GREEN", "BLUE", "BLACK"], the output should be solution(crypt) = 12, because there are 12 possible valid solutions:

54889 + 6138 = 61027
18559 + 2075 = 20634
72449 + 8064 = 80513
48229 + 5372 = 53601
47119 + 5261 = 52380
36887 + 4028 = 40915
83447 + 9204 = 92651
74655 + 8326 = 82981

in c++ wihttu comments

Pensamento

Solving cryptarithm problem

The user wants a C++ solution with comments for counting valid cryptarithm solutions, where letters are mapped to unique digits. The problem involves ensuring leading letters aren’t mapped to zero, which is key for the validity of the solution. It seems like a backtracking approach with pruning could work well here. I'll provide a code implementation with explanations and comments. There's no need for browsing since the problem is well-defined and based on common algorithms.

Thought for 7 seconds

Resposta

Below is a compact, fully-commented C++17 program that counts all valid assignments for a “word + word = word” cryptarithm under the usual rules (distinct digits, no leading zero on multi-digit words).

cpp
#include <bits/stdc++.h> using namespace std; /* Count the number of solutions of a cryptarithm word1 + word2 = word3 -------------------------------------------------------------------- • Each different uppercase letter must map to a different decimal digit 0-9. • A leading letter of any multi-digit word may NOT be 0. -------------------------------------------------------------------- Algorithm (classic column–wise back-tracking with pruning): 1. Collect the set of distinct letters (≤10 by the pigeon-hole rule). 2. Work column-by-column from least-significant (rightmost) to most-significant (leftmost). Carry is threaded through recursion. 3. When we meet a letter that is still unassigned, try every still-free digit that respects the “no leading zero” rule for that word. 4. Prune immediately when the current column sum (d1 + d2 + carry) cannot match the already-assigned digit of word3 (mod 10). 5. When we reach the end of the longest word, a carry of 0 means we found a complete valid assignment → increment the counter. Complexity: worst-case 10! (≈3.6 M) assignments, but the column pruning makes typical instances (even “SEND+MORE=MONEY”) very fast. */ struct CryptCounter { array<int, 26> letter2digit; // -1 if unassigned, else 0-9 int usedMask = 0; // bit i set ⇒ digit i already used vector<string> words; // reversed for easy indexing int maxLen; // length of longest word int solutionCount = 0; // convenience: return digit for letter idx (0-25) or -1 if unassigned inline int d(int idx) const { return letter2digit[idx]; } // Recursively solve column by column void dfs(int col, int row, int carry) { if (col == maxLen) { // past leftmost column if (carry == 0) ++solutionCount; return; } if (row < 3) { // process word[row] at this column const string &w = words[row]; int letter = (col < (int)w.size()) ? w[col] - 'A' : -1; if (letter == -1) { // this word has no letter here (implicit 0) dfs(col, row + 1, carry); return; } int digit = d(letter); bool leading = (col == (int)w.size() - 1 && w.size() > 1); // leftmost char if (row < 2) { // operands: choose / check digit freely if (digit != -1) { dfs(col, row + 1, carry + digit); } else { for (int x = 0; x <= 9; ++x) { if (usedMask & (1 << x)) continue; if (x == 0 && leading) continue; // no leading 0 letter2digit[letter] = x; usedMask |= 1 << x; dfs(col, row + 1, carry + x); usedMask &= ~(1 << x); letter2digit[letter] = -1; } } } else { // row == 2 → result word: must satisfy sum %10 int sum = carry % 10; if (digit != -1) { if (digit != sum) return; dfs(col + 1, 0, carry / 10); } else { if (usedMask & (1 << sum)) return; if (sum == 0 && leading) return; letter2digit[letter] = sum; usedMask |= 1 << sum; dfs(col + 1, 0, carry / 10); usedMask &= ~(1 << sum); letter2digit[letter] = -1; } } } } }; // API wrapper ----------------------------------------------------------- long long solution(const vector<string> &crypt) { CryptCounter cc; cc.letter2digit.fill(-1); cc.words.resize(3); // reverse words for column-wise indexing from right cc.maxLen = 0; for (int i = 0; i < 3; ++i) { cc.words[i] = string(crypt[i].rbegin(), crypt[i].rend()); cc.maxLen = max(cc.maxLen, (int)crypt[i].size()); } cc.dfs(0, 0, 0); return cc.solutionCount; } // ------------------------------- demo ---------------------------------- #ifdef RUN_DEMO int main() { vector<string> test1 = {"SEND", "MORE", "MONEY"}; cout << solution(test1) << '\n'; // prints 1 vector<string> test2 = {"GREEN", "BLUE", "BLACK"}; cout << solution(test2) << '\n'; // prints 12 } #endif

How to use it

  1. Drop the code into a file (e.g. cryptarithm.cpp),
  2. Compile with a C++17-capable compiler:
bash
g++ -std=c++17 -O2 cryptarithm.cpp -o cryptarithm
  1. Define RUN_DEMO (e.g. -DRUN_DEMO) if you’d like the two sample cases to run automatically:
bash
g++ -std=c++17 -O2 -DRUN_DEMO cryptarithm.cpp -o cryptarithm ./cryptarithm # should print: 1 then 12

Feel free to integrate the solution() routine into any contest harness or testing framework you like—its only input is the vector<string> describing the three words, and it returns the total number of distinct valid assignments.

Compartilhar esta Q&A