SEND + MORE = MONEY

using System;
using System.Collections.Generic;
using System.Linq;

class Program {
    static int ToInt(string s, int[] map) {
        int x = 0;
        foreach (var c in s) {
            x = 10 * x + map[c];
            if (x == 0 && s.Length > 1) return -1; // leading zero
        }
        return x;
    }

    static void Solve_1(int p, char[] cs, int used, int[] map, string[] ss) {
        if (p == cs.Length) {
            var a = ss.Take(ss.Length - 1).Select(e => ToInt(e, map));
            if (a.Contains(-1)) return; // 不正な変換結果

            int b = ToInt(ss.Last(), map);
            if (a.Sum() == b) {
                Console.WriteLine("{0} = {1}", string.Join(" + ", ss.Take(ss.Length - 1)), ss.Last());
                Console.WriteLine("{0} = {1}", string.Join(" + ", a), b);
            }
            return;
        }

        for (int i = 0; i < 10; i++) {
            if ((used & (1 << i)) != 0) continue;

            map[cs[p]] = i; // cs[p] に i を割り当てる
            Solve_1(p + 1, cs, used | (1 << i), map, ss);
        }
    }

    static void Solve(params string[] ss) {
        var cs = new HashSet<char>(ss.SelectMany(e => e)).ToArray();
        if (cs.Length > 10) throw new Exception(); // 10 種類より多いと数字を割り当てられない

        var map = new int[128]; // どの文字にどの数字を割り当てたか
        Solve_1(0, cs, 0, map, ss);
        Console.WriteLine();
    }

    static void Main() {
        Solve("SEND", "MORE", "MONEY");
        Solve("CROSS", "ROADS", "DANGER");
        Solve("SIX", "SEVEN", "SEVEN", "TWENTY");
    }
}

実行結果です。

$ time mono a.exe
SEND + MORE = MONEY
9567 + 1085 = 10652

CROSS + ROADS = DANGER
96233 + 62513 = 158746

SIX + SEVEN + SEVEN = TWENTY
650 + 68782 + 68782 = 138214

mono a.exe  5.38s user 0.03s system 99% cpu 5.419 total

リンク