|  | 
|  | 1 | +#include "alphametics.h" | 
|  | 2 | + | 
|  | 3 | +#include <string> | 
|  | 4 | +#include <vector> | 
|  | 5 | +#include <map> | 
|  | 6 | +#include <optional> | 
|  | 7 | +#include <algorithm> | 
|  | 8 | +#include <sstream> | 
|  | 9 | +#include <unordered_set> | 
|  | 10 | + | 
|  | 11 | +namespace alphametics { | 
|  | 12 | + | 
|  | 13 | +std::optional<std::map<char,int>> solve(const std::string& puzzle) { | 
|  | 14 | +    auto sep = puzzle.find("=="); | 
|  | 15 | +    if (sep == std::string::npos) return std::nullopt; | 
|  | 16 | +    std::string left = puzzle.substr(0, sep); | 
|  | 17 | +    std::string right = puzzle.substr(sep + 2); | 
|  | 18 | + | 
|  | 19 | +    auto trim = [&](std::string& s) { | 
|  | 20 | +        auto b = s.find_first_not_of(' '); | 
|  | 21 | +        auto e = s.find_last_not_of(' '); | 
|  | 22 | +        s = (b == std::string::npos) ? std::string() : s.substr(b, e - b + 1); | 
|  | 23 | +    }; | 
|  | 24 | +    trim(left); trim(right); | 
|  | 25 | + | 
|  | 26 | +    std::vector<std::string> addends; | 
|  | 27 | +    std::istringstream iss(left); | 
|  | 28 | +    for (std::string part; std::getline(iss, part, '+'); ) { | 
|  | 29 | +        trim(part); | 
|  | 30 | +        addends.push_back(part); | 
|  | 31 | +    } | 
|  | 32 | +    trim(right); | 
|  | 33 | +    std::string result = right; | 
|  | 34 | + | 
|  | 35 | +    std::vector<char> letters; | 
|  | 36 | +    std::unordered_set<char> seen, leading; | 
|  | 37 | +    auto collect = [&](const std::string& w) { | 
|  | 38 | +        if (w.size() > 1) leading.insert(w.front()); | 
|  | 39 | +        for (char c : w) { | 
|  | 40 | +            if (seen.insert(c).second) letters.push_back(c); | 
|  | 41 | +        } | 
|  | 42 | +    }; | 
|  | 43 | +    for (auto& w : addends) collect(w); | 
|  | 44 | +    collect(result); | 
|  | 45 | +    if (letters.size() > 10) return std::nullopt; | 
|  | 46 | + | 
|  | 47 | +    int n = letters.size(); | 
|  | 48 | +    std::map<char,int> idx; | 
|  | 49 | +    for (int i = 0; i < n; ++i) idx[letters[i]] = i; | 
|  | 50 | +    std::vector<long long> weight(n, 0); | 
|  | 51 | + | 
|  | 52 | +    for (auto& w : addends) { | 
|  | 53 | +        long long mult = 1; | 
|  | 54 | +        for (int i = (int)w.size() - 1; i >= 0; --i) { | 
|  | 55 | +            weight[idx[w[i]]] += mult; | 
|  | 56 | +            mult *= 10; | 
|  | 57 | +        } | 
|  | 58 | +    } | 
|  | 59 | +    { | 
|  | 60 | +        long long mult = 1; | 
|  | 61 | +        for (int i = (int)result.size() - 1; i >= 0; --i) { | 
|  | 62 | +            weight[idx[result[i]]] -= mult; | 
|  | 63 | +            mult *= 10; | 
|  | 64 | +        } | 
|  | 65 | +    } | 
|  | 66 | + | 
|  | 67 | +    std::vector<bool> used(10, false); | 
|  | 68 | +    std::map<char,int> assign; | 
|  | 69 | +    bool found = false; | 
|  | 70 | +    std::map<char,int> solution; | 
|  | 71 | +    std::function<void(int,long long)> dfs = [&](int pos, long long sum) { | 
|  | 72 | +        if (found) return; | 
|  | 73 | +        if (pos == n) { | 
|  | 74 | +            if (sum == 0) { found = true; solution = assign; } | 
|  | 75 | +            return; | 
|  | 76 | +        } | 
|  | 77 | +        char c = letters[pos]; | 
|  | 78 | +        for (int d = 0; d < 10 && !found; ++d) { | 
|  | 79 | +            if (used[d] || (d == 0 && leading.count(c))) continue; | 
|  | 80 | +            used[d] = true; | 
|  | 81 | +            assign[c] = d; | 
|  | 82 | +            dfs(pos + 1, sum + weight[pos] * d); | 
|  | 83 | +            used[d] = false; | 
|  | 84 | +        } | 
|  | 85 | +    }; | 
|  | 86 | + | 
|  | 87 | +    dfs(0, 0); | 
|  | 88 | +    if (found) return solution; | 
|  | 89 | +    return std::nullopt; | 
|  | 90 | +} | 
|  | 91 | + | 
|  | 92 | +} // namespace alphametics | 
0 commit comments