Of course, I don't like computer response times that are in the seconds rather than the sub-seconds range, so I had to find a better way to get the answer. I did some searching, and I saw a lot of references to various approaches. None of them seems to be appropriate for me as a suitable solution for encoding into APL, until I found a paper on using a genetic algorithm. That gave me some inspiration based on the Hill climbing algorithms that are used in things like the N-queens problem.
Basically, I used the fitness function from the genetic algorithm paper to do a greedy local search (hill climbing) algorithm; the approach actually matches pretty closely to the genetic algorithm, but the genetic algorithm uses parallelism and a number of other things, such as multiple agents and populations. Instead, I did a straightforward local search weighted on the fitness function. To deal with the possibility of local but not global maxima, I again borrowed from the genetic algorithm to choose any random swap of two assignments.
And without further ado, here's the algorithm in a simple APL program.
∇Z←SOLVE∆SMM;CHARS;X;B;SEND;MORE;MONEY;OLD;CONFLICTS;SWAP;I;J;GOOD;MS  ⍝ Solve the SEND+MORE=MONEY Cryptarithmetic problem  ⍝ using local search and minimum conflict heuristics.  ⍝  ⍝ Create selection vectors for the elements  CHARS←'demnorsy'  SEND←CHARS⍳'send' ⋄ MORE←CHARS⍳'more' ⋄ MONEY←CHARS⍳'money'  MS←CHARS⍳'ms'  ⍝  ⍝ Choose a variable assignment X randomly to start with.  X←(10?10)-⎕IO  ⍝  ⍝ Fix fitness, swap, and correctness functions  ⊣⎕FX 'Z←CONFLICTS X' 'Z←(10⊥X[MONEY])-(10⊥X[MORE])+10⊥X[SEND]'  ⊣⎕FX 'Z←I (X SWAP) J' 'Z←X' 'Z[I J]←Z[J I]'  ⊣⎕FX 'Z←GOOD X' 'Z←0^.≠X[MS]'  ⍝  ⍝ Check for finished product  LP:→((0^.≠X[MS])^0=CONFLICTS X)/XT  ⍝  ⍝ Compute the possible choices  B←(GOOD¨B)/B←∪,(⍳10)∘.(X SWAP)⍳10  ⍝  ⍝ Take the swap that minimizes the conflicts  OLD←X ⋄ X←⊃B[↑⍋|CONFLICTS¨B]  →(OLD≢X)/LP ⋄ (I J)←(2?10) ⋄ X[I J]←X[J I] ⋄ →LP  ⍝  ⍝ We are done and complete  XT:Z←2 8⍴'DEMNORSY',X[⍳8] ∇
Now, the real question is, how fast does this thing go? Is it faster than my brute force algorithm? I mean, they are both basically search algorithms. The answer: Yes! On this one, the timings jump because of the randomization that I use, but consistently, I get the answer back in under 100ms, and often under 50ms. Not bad!