По следам вопроса Ребус: VOLVO+FIAT=MOTOR.
Каждая буква – это цифра, разным буквам соответствуют разные цифры.
Необходимо заменить буквы цифрами так, чтобы получилось верное
равенство. Найти все решения (если есть несколько ).
Задача такая же, но слова могут быть произвольные, а не только именно эти.
Ответы
Ответ 1
Гм. Когда-то давно писал под свои нужды, умеет немного больше, чем просто арифметика
- например, VOLVO+FIAT=MOTOR**Q! (в смысле - факториал, возведение в степень, квадратный
корень... да даже системы уравнений :) - типа a+b=c; 2*a+3*b=8 в командной строке.
Понимает русские буквы. Сносить два этажа и резать, гм... ну, вы поняли, как в анекдоте
- не буду :)
Многопоточность.
Использовал немного модифицированный YACC, так что теперь не знаю, что и давать:
YACC'овский файл или С++ :)
Держите C++. Чистить лень :(
#define _CRT_SECURE_NO_WARNINGS
#define NDEBUG
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline long long ipow(long long x, long long p)
{
if (x == 0 || x == 1) return x;
long long r = 1;
while(p)
{
if (p&0x1) r*= x;
x *= x;
p >>= 1;
}
return r;
}
inline unsigned long long isqrt(unsigned long long x)
{
unsigned long long x1, g0, g1;
if (x <= 1) return x;
int s = 1;
x1 = x - 1;
if (x1 > 0xFFFFFFFF) { s = s + 16; x1 >>= 32; }
if (x1 > 0xFFFF) { s = s + 8; x1 >>= 16; }
if (x1 > 0xFF) { s = s + 4; x1 >>= 8; }
if (x1 > 0xF) { s = s + 2; x1 >>= 4; }
if (x1 > 0x3) { s = s + 1; }
g0 = 1ll << s;
g1 = (g0 +(x>>s)) >> 1;
while( g1 < g0) {
g0 = g1;
g1 = (g0 + (x/g0)) >> 1;
}
return g0;
}
long long fact(long long x)
{
assert(x <= 20);
static long long vals[21] = {1,1,2,6,24,120,720,5040,0,0,0,0,0,0,0,0,0,0,0,0,0};
if (vals[x]) return vals[x];
long long s = 1;
for(int i = 1; i <= x; ++i)
{
s *= i;
vals[i] = s;
}
return s;
}
long long bifact(long long x)
{
assert(x <= 32);
static long long vals[33] = {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
if (vals[x]) return vals[x];
long long s = 1;
for(int i = 1; i <= 31; i += 2)
{
s *= i;
vals[i] = s;
}
s = 1;
for(int i = 2; i <= 32; i += 2)
{
s *= i;
vals[i] = s;
}
return vals[x];
}
typedef long long ALM_STYPE;
static int alm_parse( void * alm_param );
#define Number 257
#define Wrong 258
#define uminus 259
#define alm_IntError
#define alm_clearin alm_char = -1
#define alm_errok alm_errflag = 0
#ifndef ALM_MAXDEPTH
#define ALM_MAXDEPTH 150
#endif
#define ALM_ERRCODE 256
template< typename RandomAccess, typename Compare >
bool next_kpermutation( RandomAccess first, RandomAccess last,
typename std::iterator_traits< RandomAccess >::difference_type k,
Compare comp )
{
typedef typename std::iterator_traits< RandomAccess >::difference_type Int;
typedef typename std::iterator_traits< RandomAccess >::value_type Val;
if( first == last ) return false;
Int n = std::distance(first, last);
if (k > n) return false;
//Int n = distance(first, last);
//Int i = -1;
RandomAccess i = last;
for(RandomAccess j = first + k - 1;
j >= first; --j)
{
if (std::max_element(j,last) != j)
{
i = j;
break;
}
}
if (i == last) return false;
{
// Сначала ищем первый, больший p_[i]
RandomAccess j = i;
++j;
while(!comp(*i,*j)) ++j;
RandomAccess imin = j; // Индекс минимального
for(; j != last; ++j)
{
if (comp(*i,*j) &&
comp(*j,*imin))
{
imin = j;
}
}
std::swap( *i, *imin );
++i;
}
RandomAccess u = first + std::min(k,n-1);
while ( i < u )
{
RandomAccess imin = i;
for(RandomAccess j = i + 1; j != last; ++j)
{
if (comp(*j,*imin)) imin = j;
}
std::swap( *i, *imin );
++i;
}
return true;
}
template< typename RandomAccess >
bool next_kpermutation( RandomAccess first, RandomAccess last, int k )
{
return ( next_kpermutation( first, last, k,
std::less< typename std::iterator_traits< RandomAccess
>::value_type >( )
) );
}
static void alm_error(int) {}
static int alm_lex(void*qq,ALM_STYPE*alm_lval)
{
const char *& alm_textpointer = *(const char **)qq;
while(*alm_textpointer==' ' /*||*alm_textpointer=='\t' */) ++alm_textpointer;
switch(*alm_textpointer)
{
case 0: return EOF;
case '0':
{
if (isdigit(*(alm_textpointer+1))) return Wrong;
}
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
{
*alm_lval = 0;
while(*alm_textpointer >= '0' && *alm_textpointer <= '9')
{
*alm_lval = (*alm_lval)*10 + (*alm_textpointer - '0');
++alm_textpointer;
}
return Number;
} break;
case '*':
if (*(alm_textpointer+1) == '*')
{
alm_textpointer += 2;
return '^';
}
case '+':
case '-':
case '(':
case ')':
case '/':
case '=':
case '^':
case ';':
case '!':
case '#':
case '%':
{
*alm_lval = 0;
return *alm_textpointer++;
} break;
}
++alm_textpointer;
return Wrong;
}
mutex mx;
int total_count = 0;
void almetis(int begin, int end,
const char * buf, const char * symbols, int symno)
{
char digs[] = "0123456789";
int no = 0;
do {
if (no >= end) break;
if (no < begin) continue;
char stmt[2048];
const char * c = buf;
char * t = stmt;
for(;*c; ++c,++t)
{
switch(*c)
{
case ' ':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '(':
case ')':
case '+':
case '-':
case '*':
case '/':
case '=':
case '^':
case ';':
case '!':
case '#':
case '%':
case '\t':
case '\r':
case '\n': *t = *c; break;
default:
for(int j = 0; j < symno; ++j)
{
if (*c == symbols[j])
{
*t = digs[j];
break;
}
}
}
}
*t = 0;
const char * q = stmt;
if (alm_parse(&q) == 0)
{
lock_guard lk(mx);
total_count++;
printf("%s\n",stmt);
}
} while(++no, next_kpermutation(digs,digs+10,symno));
};
int main(int argc, char* argv[])
{
setlocale(LC_ALL,"Rus");
int threads = thread::hardware_concurrency();
if (threads <= 1) threads = 1;
else if (threads > 6) threads = 6;
printf("Threads: %d\n",threads);
char buf[2048] = { 0 };
for(int i = 1; i < argc; ++i)
{
strcat_s(buf,2048,argv[i]);
if (i != argc-1) strcat_s(buf,2048," ");
}
char symbols[11] = { 0 };
int symno = 0;
for(const char * c = buf; *c; ++c)
{
if (strchr(" 01234567890()+-*/=^;#%!\t\r\n",*c)) continue;
bool found = false;
for(int j = 0; j < symno; ++j)
if (symbols[j] == *c)
{
found = true;
break;
}
if (!found) symbols[symno++] = *c;
if (symno == 11)
{
fprintf(stderr,"Too many symbols\n");
return 1;
}
}
printf("There are %d symbols: %s\n",symno,symbols);
int count = 1;
for(int i = 0; i < symno; ++i) count *= (10-i);
if ((count < 5000) || (threads == 1))
{
almetis(0,count,buf,symbols,symno);
}
else
{
int part = count / threads;
assert(threads * part == count);
vector> fus;
for(int i = 0; i < threads; ++i)
{
fus.push_back(async(almetis,i*part,(i+1)*part,buf,symbols,symno));
}
for(auto& x: fus) x.get();
}
printf("Solutions: %d\n",total_count);
}
static const int alm_exca[] ={
-1, 1,
0, -1,
-2, 0,
};
#define ALM_NPROD 22
#define ALM_LAST 228
static const int alm_act[]={
9, 13, 4, 2, 9, 10, 1, 20, 8, 10,
7, 21, 8, 0, 7, 33, 17, 15, 20, 16,
20, 19, 21, 0, 21, 20, 0, 17, 15, 21,
16, 0, 19, 5, 17, 15, 20, 16, 0, 19,
21, 0, 0, 6, 0, 17, 14, 26, 0, 0,
19, 22, 23, 24, 25, 0, 0, 0, 27, 28,
29, 30, 31, 32, 0, 0, 0, 0, 18, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 18,
0, 18, 0, 0, 0, 0, 18, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 18, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 11, 12, 0, 0, 11, 12 };
static const int alm_pact[]={
-35, -1000, -1000, -1000, -58, -1000, -15, -31, -31, -31,
-31, -1000, -1000, -31, -31, -31, -31, -31, -31, -31,
-1000, -1000, -13, -13, -1000, -26, -1000, -8, 3, 3,
-13, -13, -13, -1000 };
static const int alm_pgo[]={
0, 6, 3, 2, 33, 43 };
static const int alm_r1[]={
0, 1, 1, 2, 2, 3, 3, 4, 4, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5 };
static const int alm_r2[]={
0, 1, 1, 1, 2, 3, 1, 3, 1, 3,
3, 2, 2, 3, 3, 3, 2, 2, 2, 3,
1, 1 };
static const int alm_chk[]={
-1000, -1, -2, 256, -3, -4, -5, 45, 43, 35,
40, 257, 258, 59, 61, 43, 45, 42, 94, 47,
33, 37, -5, -5, -5, -5, -4, -5, -5, -5,
-5, -5, -5, 41 };
static const int alm_def[]={
0, -2, 1, 2, 3, 6, 8, 0, 0, 0,
0, 20, 21, 4, 0, 0, 0, 0, 0, 0,
16, 17, 11, 12, 18, 0, 5, 7, 9, 10,
13, 14, 15, 19 };
#define YACC_MEM_STACK
//#define alm_IntError
#ifdef alm_IntError
#define alm_errNoMemory -1
#define alm_errStackOvr -2
#define alm_errSyntax -3
#else
#define alm_errNoMemory "not enough memory"
#define alm_errStackOvr "internal stack overflow"
#define alm_errSyntax "syntax error"
#endif
#define ALM_FLAG (-1000)
#define ALM_ERROR goto alm_errlab
#define ALM_ACCEPT return(0)
#define ALM_ABORT return(1)
#if defined(YACC_MEM_HEAP)
template
class alm__memory
{
T * ptr_;
public:
alm__memory(unsigned int size)
{
ptr_ = new T[size];
};
~alm__memory()
{
delete[] ptr_;
};
T* ptr()
{
return ptr_;
};
};
#endif
static int alm_parse( void * alm_param )
{
ALM_STYPE alm_lval = ALM_STYPE(), alm_val = ALM_STYPE();
int alm_char = -1;
int alm_nerrs = 0;
int alm_errflag = 0;
#if defined(YACC_MEM_HEAP)
int * alm_s;
ALM_STYPE * alm_v;
#endif
#if defined(YACC_MEM_STACK)
int alm_s[ALM_MAXDEPTH+2];
ALM_STYPE alm_v[ALM_MAXDEPTH+2];
#endif
int alm_j, alm_m;
ALM_STYPE * alm_pvt;
int alm_state, *alm_ps, alm_n;
ALM_STYPE * alm_pv;
const int * alm_xi;
#if defined(YACC_MEM_HEAP)
alm__memory ALM__M (ALM_MAXDEPTH+2);
alm__memory ALM__M1(ALM_MAXDEPTH+2);
alm_v = ALM__M.ptr();
alm_s = ALM__M1.ptr();
if ((alm_v == NULL) || (alm_s == NULL))
{
alm_error(alm_errNoMemory);
return(1);
};
#endif
alm_state = 0;
alm_char = -1;
alm_nerrs = 0;
alm_errflag = 0;
alm_ps = &alm_s[-1];
alm_pv = &alm_v[-1];
alm_stack:
if( ++alm_ps > &alm_s[ALM_MAXDEPTH] )
{
alm_error(alm_errStackOvr);
return(1);
}
*alm_ps = alm_state;
++alm_pv;
*alm_pv = alm_val;
alm_newstate:
alm_n = alm_pact[alm_state];
if( alm_n <= ALM_FLAG )
goto alm_default;
if( alm_char < 0 )
if( (alm_char = (int )alm_lex(alm_param,&alm_lval)) < 0 )
alm_char = 0;
if( (alm_n += alm_char) < 0 || alm_n >= ALM_LAST )
goto alm_default;
if( alm_chk[alm_n = alm_act[alm_n]] == alm_char )
{
alm_char = -1;
alm_val = alm_lval;
alm_state = alm_n;
if( alm_errflag > 0 )
--alm_errflag;
goto alm_stack;
}
alm_default:
if( (alm_n = alm_def[alm_state]) == -2 )
{
if( alm_char < 0 )
if( (alm_char = (int )alm_lex(alm_param,&alm_lval)) < 0 )
alm_char = 0;
for(alm_xi=alm_exca; (*alm_xi!=(-1)) || (alm_xi[1]!=alm_state);alm_xi+=2)
;
while( *(alm_xi += 2) >= 0 )
if( *alm_xi == alm_char )
break;
if( (alm_n = alm_xi[1]) < 0 )
return(0);
}
if( alm_n == 0 )
{
switch( alm_errflag )
{
case 0:
alm_error(alm_errSyntax);
alm_errlab:
++alm_nerrs;
case 1:
case 2:
alm_errflag = 3;
while ( alm_ps >= alm_s )
{
alm_n = alm_pact[*alm_ps] + ALM_ERRCODE;
if( alm_n >= 0 && alm_n < ALM_LAST &&
alm_chk[alm_act[alm_n]] == ALM_ERRCODE )
{
alm_state = alm_act[alm_n];
goto alm_stack;
}
alm_n = alm_pact[*alm_ps];
--alm_ps;
--alm_pv;
}
alm_abort:
return(1);
case 3:
if( alm_char == 0 )
goto alm_abort;
alm_char = -1;
goto alm_newstate;
}
}
alm_ps -= alm_r2[alm_n];
alm_pvt = alm_pv;
alm_pv -= alm_r2[alm_n];
alm_val = alm_pv[1];
alm_m = alm_n;
alm_n = alm_r1[alm_n];
alm_j = alm_pgo[alm_n] + *alm_ps + 1;
if( alm_j >= ALM_LAST || alm_chk[alm_state = alm_act[alm_j]] != -alm_n )
alm_state = alm_act[alm_pgo[alm_n]];
switch(alm_m)
{
case 1:{
return alm_pvt[-0] ? 0 : -1;
} break;
case 2:{
return -1;
} break;
case 3:{
alm_val = alm_pvt[-0];
} break;
case 4:{
alm_val = alm_pvt[-1];
} break;
case 5:{
if (alm_pvt[-0] == 0) return -1;
alm_val = alm_pvt[-2] && alm_pvt[-0];
} break;
case 6:{
if (alm_pvt[-0] == 0) return -1;
alm_val = alm_pvt[-0];
} break;
case 7:{
alm_val = (alm_pvt[-2] == alm_pvt[-0]) ? 1 : 0;
} break;
case 8:{
alm_val = (alm_pvt[-0] == 0) ? 1 : 0;
} break;
case 9:{
alm_val = alm_pvt[-2] + alm_pvt[-0];
} break;
case 10:{
alm_val = alm_pvt[-2] - alm_pvt[-0];
} break;
case 11:{
alm_val = -alm_pvt[-0];
} break;
case 12:{
alm_val = alm_pvt[-0];
} break;
case 13:{
alm_val = alm_pvt[-2] * alm_pvt[-0];
} break;
case 14:{
if (alm_pvt[-0] < 0) return -1;
alm_val = 1;
for(int i = 0; i < alm_pvt[-0]; ++i) alm_val *= alm_pvt[-2];
} break;
case 15:{
if (alm_pvt[-0] == 0) return -1;
alm_val = alm_pvt[-2] / alm_pvt[-0];
if (alm_val*alm_pvt[-0] != alm_pvt[-2]) return -1;
} break;
case 16:{
if (alm_pvt[-1] < 0) return -1;
if (alm_pvt[-1] >=20) return -1;
alm_val = fact(alm_pvt[-1]);
} break;
case 17:{
if (alm_pvt[-1] < 0) return -1;
if (alm_pvt[-1] >=33) return -1;
alm_val = bifact(alm_pvt[-1]);
} break;
case 18:{
if (alm_pvt[-1] < 0) return -1;
alm_val = isqrt(alm_pvt[-0]);
if (alm_val*alm_val != alm_pvt[-0]) return -1;
} break;
case 19:{
alm_val = alm_pvt[-1];
} break;
case 20:{
alm_val = alm_pvt[-0];
} break;
case 21:{
return -1;
} break;
}
goto alm_stack;
}
Монстр, претендующий скорее на универсальность, чем на красоту. Поэтому по сравнению
со специализированными программами, понятно, будет тормознее...
Тут - https://ideone.com/GHbA34 - переправленная для ввода из stdin версия. Кстати,
почему-то работает на Ideone медленно, на моей машине исходное уравнение в 4 потока
ковыряет примерно 0.25с (полное время работы программы).
Ответ 2
document.querySelector("form").addEventListener('submit', function (e) {
e.preventDefault();
var aaa = document.getElementById("a").value;
var bbb = document.getElementById("b").value;
var ccc = document.getElementById("c").value;
var all = (aaa + bbb + ccc).replace(/(.)(?=.*\1)/g, "");
var abc = (aaa.charAt(1) && aaa[0]) + (bbb.charAt(1) && bbb[0]) + (ccc.charAt(1)
&& ccc[0]);
console.log(`${aaa} + ${bbb} = ${ccc}`);
var code = `(function () {
var ${all.split("")};
var used = 0;
var _${aaa}, _${bbb}, _${ccc};
` + all.split("").map(c=>
`for (X=0; X<10; ++X) if (!(used & (1< x.replace("\n", "\n" + r
+ "\n"), `
${[aaa,bbb,ccc].map(x => `_${x} = ${x.replace(/\w+/g, s=>"(".repeat(s.length)+s).replace(/\w/g,
"$&)*10+").replace(/\*10\+(?!\w)/g, "")}`).join("\n")}
if(_${aaa} + _${bbb} === _${ccc}) console.log(_${aaa} + " + " + _${bbb} + " = " +
_${ccc})
`
).replace(RegExp(`([${abc}@])=0`, "g"), "$1=1") + `
})()`
//console.log(code);
eval(code);
});
.as-console-wrapper.as-console-wrapper { max-height: calc(100vh - 3em) }
Ответ 3
Вариант на F#:
[]
let main argv =
let sum1 = "VOLVO"
let sum2 = "FIAT"
let res = "MOTOR"
let wordToInt(word : string, map : Map) =
word.ToCharArray() |> Array.map(fun ch -> map.[ch]) |> Array.reduce(fun n1
n2 -> n1 * 10 + n2)
let checkSolution(map : Map) =
let s1 = wordToInt(sum1, map)
let s2 = wordToInt(sum2, map)
let resInt = s1 + s2
let resNums = resInt.ToString().ToCharArray() |> Array.map(fun ch -> ch.ToString()
|> int)
if resNums.Length <> res.Length then
List.empty
else
let pairs = res.ToCharArray() |> Array.mapi(fun i ch -> (resNums.[i], ch))
let existingCharsFailed = pairs |> Array.exists(fun (num, ch) -> if map.ContainsKey(ch)
then map.[ch] <> num else false)
if existingCharsFailed then
List.empty
else
let newChars = pairs |> Array.where(fun (num, ch) -> not(map.ContainsKey(ch)))
if newChars |> Array.exists(fun (num1, ch1) -> newChars |> Array.exists(fun
(num2, ch2) -> ch1 = ch2 && num1 <> num2)) then
List.empty
else
if newChars |> Array.exists(fun (num1, ch2) -> map |> Map.exists(fun
ch2 num2 -> num1 = num2)) then
List.empty
else
[(s1, s2)]
let rec find(index : int, chs : char[], set : Set, map : Map) =
if index < chs.Length then
set |> Set.toList
|> List.map(fun i -> find(index + 1, chs, set.Remove(i), map.Add(chs.[index], i)))
|> List.reduce(fun sol1 sol2 -> sol1 @ sol2)
else
checkSolution(map)
let summandChars = (sum1 + sum2).ToCharArray() |> Array.distinct
let solutions = find(0, summandChars, set [0..9], Map.empty)
for (s1, s2) in solutions |> List.sortBy(fun (s1, s2) -> s1) do
printfn "%d+%d=%d" s1 s2 (s1 + s2)
0
Ответ 4
Вариант на C# на массивах без Dictionary, возможно не очень понятный, зато быстрый.
Что бы перебрать все возможные перестановки используется цикл до общего их количества.
Например, если у нас 6 символов, первый символ может быть любой (10 вариантов), для
второго символа остается 9 вариантов, и т.д. Получается, количество перестановок равно:
10 * 9 * 8 * 7 * 6 * 5.
Дальше цикл раскручивает число в перестановку. Массив num содержит цифры, которые
остались для выбора. Он "обнуляется" каждый раз: for (int j = 0; j < 10; j++) num[j]
= j; Как только мы выбрали очередную цифру, она удаляется с массива: for (int k = mapNum;
k < depth; k++)
Цифры выбираются как остатки от деления, сначала на 10, потом на 9 (так как остается
только 9 цифр для выбора), и т.д.
static void Main(string[] args)
{
string sum1 = "VOLVO";
string sum2 = "FIAT";
string res = "MOTOR";
char[] chars = (sum1 + sum2 + res).Distinct().ToArray();
if (chars.Length > 10)
Console.WriteLine("No solutions");
else
{
int permutations = 1;
for (int i = 11 - chars.Length; i <= 10; i++)
permutations *= i;
int[] map = new int[256];
int[] num = new int[10];
for (int i = 0; i < permutations; i++)
{
for (int j = 0; j < 10; j++)
num[j] = j;
int depth = 10;
int index = i;
for (int j = 0; j < chars.Length; j++)
{
int mapNum = index % depth;
map[chars[j]] = num[mapNum];
index /= depth;
depth--;
for (int k = mapNum; k < depth; k++)
num[k] = num[k + 1];
}
int num1 = 0;
for (int j = 0; j < sum1.Length; j++)
num1 = num1 * 10 + map[sum1[j]];
int num2 = 0;
for (int j = 0; j < sum2.Length; j++)
num2 = num2 * 10 + map[sum2[j]];
int resn = 0;
for (int j = 0; j < res.Length; j++)
resn = resn * 10 + map[res[j]];
if (num1 + num2 == resn)
Console.WriteLine($"{num1}+{num2}={resn}");
}
}
}
Ответ 5
find(...parse("VOLVO + FIAT == MOTOR"));
function parse(expr) {
var letters = [...new Set(expr.match(/\w/g))];
var words = [...new Set(expr.match(/\w+/g))];
var defs = words.map(w => `const ${w} = ` +
[...w].map((l, i) => `${l} * ${Math.pow(10, w.length - i - 1)}`).join(" + ")
).join("\n");
var q1 = `function ([${letters.join(", ")}]) {
${defs}
return ${expr};
}`;
var quotedExpr = "`" + expr.replace(/\w+/g, w => "${" + w + "}") + "`";
var q2 = `function ([${letters.join(", ")}]) {
${defs}
return ${quotedExpr};
}`;
return new Function (`return [${q1}, ${q2}]`)();
}
function find(pred, fn) {
const digits = [0,1,2,3,4,5,6,7,8,9];
do {
if (pred(digits))
console.log(fn(digits));
let i;
for (i = 1; i < digits.length; i++)
if (digits[i-1] < digits[i])
break;
if (i == digits.length) break;
let j;
for (let k = 0; k
Ответ 6
Вариант на C#:
void Main()
{
var word1 = "VOLVO";
var word2 = "FIAT";
var word3 = "MOTOR";
var letters = string.Concat(word1,word2,word3).Distinct();
var distinctLetters = letters.Count();
if( distinctLetters > 10)
return;
var minNum = (int)Math.Pow(10, distinctLetters-1);
var maxNum = (int)Math.Pow(10, distinctLetters) - 1;
for(var i = minNum; i < maxNum; i++)
{
var dict = MakeDict(letters, i);
if(!IsEnabled(dict))
continue;
if(!IsSuitable(word1, word2, word3, dict))
continue;
dict.Dump();
}
}
// Define other methods and classes here
bool IsSuitable(string word1, string word2, string word3, Dictionary dict)
{
int a1 = Convert(word1, dict);
int a2 = Convert(word2, dict);
int a3 = Convert(word3, dict);
return a1 + a2 == a3;
}
int Convert(string word, Dictionary dict)
{
var j = word.Length;
int result = 0;
foreach (var element in word)
{
int pos = dict[element];
result += pos * (int)Math.Pow(10, j);
j--;
}
return result;
}
bool IsEnabled(Dictionary data)
{
// Каждая цифра может быть закреплена только за одной буквой
return data.Select(x => x.Value)
.GroupBy(x => x)
.Select(g => new { Name = g.Key, Count = g.Count() })
.All(x => x.Count == 1);
}
Dictionary MakeDict(IEnumerable source, int num)
{
var result = new Dictionary();
string a = num.ToString();
var i = 0;
foreach (var element in source)
{
var curChar = int.Parse(a.Substring(i, 1));
result.Add(element, curChar);
i++;
}
return result;
}
Уже после написания вижу, что можно сделано неоптимальнее и можно ещё разгонять во
многих местах.
Просто оставлю как базовую версию на c#, чтобы было от чего отталкиваться.