C 密码算法求解器分解的效率
问题如下:给定“ABC+DEF=GHI”格式字符串,其中A、B、C等表示唯一数字,请找到给出最大GHI的表达式。例如:输入字符串是AAB+AAB=AAB,则没有解决方案。如果改为AAA+BBB=AAA,则解决方案为999+000=999。另一个示例字符串:ABC+CBA=GGG,结果是=>543+345=888 我很容易就排除了不可能的情况。我心目中的算法是一种蛮力算法,它只是首先尝试最大化rhs。然而,我的问题是做得这么快,而且还要注意唯一的数字。解决这个问题的有效方法是什么 注意:我希望用单线程方法解决这个问题,我当前的问题是检测“赋值”函数中是否使用了唯一的数字。也许有更好的赋值方法 编辑:根据smci的建议,以下是我最终想要实现的目标:ABRA+CADABRA+ABRA+CADABRA==HOUDINI;7457+1797457+7457+1797457==3609828——这个系统不仅可以处理开头提供的形式I的字符串(3位数字+3位数字=3位数字),还可以处理这些字符串。不过,从简单开始,采用我给出的格式解决方案并没有什么坏处:)C 密码算法求解器分解的效率,c,algorithm,solver,decomposition,cryptarithmetic-puzzle,C,Algorithm,Solver,Decomposition,Cryptarithmetic Puzzle,问题如下:给定“ABC+DEF=GHI”格式字符串,其中A、B、C等表示唯一数字,请找到给出最大GHI的表达式。例如:输入字符串是AAB+AAB=AAB,则没有解决方案。如果改为AAA+BBB=AAA,则解决方案为999+000=999。另一个示例字符串:ABC+CBA=GGG,结果是=>543+345=888 我很容易就排除了不可能的情况。我心目中的算法是一种蛮力算法,它只是首先尝试最大化rhs。然而,我的问题是做得这么快,而且还要注意唯一的数字。解决这个问题的有效方法是什么 注意:我希望用单
#包括
#包括
#包括
#定义最大表达式大小11+1
#定义MAX_变量9
int variables_read[MAX_variables]={0};
结构变量{
int系数;
int*ptr;
内侧;
int-canhavezero;
无符号值_max;
};
typedef结构变量;
结构方程{
变量*变量[9];//最大值
右上的未签名的非重复字符;
无符号var_计数;
};
类型定义结构方程;
内部动力(内部n,内部k){
int res=1;
对于(int i=0;i变量[E->var_count++]=V;
}
int不可能(字符*表达式){
//如果所有字母相同或结尾字母相同,则没有解决方案
如果(
(表达式[0]==表达式[4]&表达式[0]==表达式[8])||
(!strncmp(表达式,表达式+4,3)和&!strncmp(表达式,表达式+8,3))
)
返回1;
返回0;
}
int赋值(等式*E,int pos,int*值){
如果(!E->变量[pos]->值\u计数){
如果(位置<0)
返回2;
//如果没有可能的值,则重置此值,但从最近的变量中获取一个值计数
E->变量[pos-1]->值_计数--;
E->variables[pos]->value\u count=E->variables[pos]->value\u max;
返回0;
}
int i;
对于(i=9;i>=0&&value[i]=-1;--i)
printf(“将%d分配给%c\n”,E->variables[pos]->value_set[E->variables[pos]->value_count-1],'A'+(E->variables[pos]->ptr-E->variables[0]->ptr));
*(E->变量[pos]->ptr)=值[i];
值[i]=-1;//我们有唯一的数字
返回0;
}
int(方程E){
整数和=0,系数=0;
printf(“正在尝试…\n”);
对于(int i=0;i系数*(*E.变量[i]->ptr);
printf(“%d”,*E.variables[i]->ptr);
if(如变量[i]->侧)
系数*=-1;
总和+=系数;
}
printf(“\nSum为%d\n”,总和);
返回!求和;
}
char*计算(char*表达式){
字符*res;
//首先检查不可能的情况
if(不可能(表达式)){
res=(char*)malloc(sizeof(char)*strlen(“没有解决方案”);
strcpy(res,“没有解决方案!”);
返回res;
}
res=(char*)malloc(sizeof(char)*最大表达式大小);
//现在试着寻找解决方案,首先将给定的字符描述为方程
方程E;
E.var_计数=0;
E.rhs=0上的不同_;
int侧_模式=0,功率计数器=0;
int a=-1,b=-1,c=-1,d=-1,e=-1,f=-1,g=-1,h=-1,i=-1;
int*max_variables[max_variables]={&a、&b、&c、&d、&e、&f、&g、&h、&i};
对于(int j=0;j系数=int_功率(10,2-(功率计数器%3));
V->ptr=max_变量[表达式[j]-'A'];
V->side=side\u模式;
E.distinct_on_rhs+=侧边_模式&!变量_读取[expression[j]-'A'];
如果(!(powcounter%3)){//数字的开头
V->value\u count=9;
V->value_max=9;
V->canhavezero=0;
}
否则{
V->value\u count=10;
V->value_max=10;
V->canhavezero=1;
}
添加变量(&E,V);
变量_read[表达式[j]-'A']=1;
++功率计数器;
}
对于(int j=0;j系数,'A'+(E.variables[j]->ptr-max_variables[0]),E.variables[j]->side);
//我们得到了方程的一个表示形式,现在试着去解它
int=0;
//O(9^N),其中N是不同变量的数量。
//我们可以做的一个优化是,我们首先将可能的最大值分配给rhs编号,然后向下。我们需要最大值。
printf(“Distincts:%d\n”,例如在右上的Distincts\u);
做{
//尝试将值分配给所有变量,并尝试是否解决了该方程
//但首先要尽可能地分配rhs最大值
int值[10]={0,1,2,3,4,5,6,7,8,9};
int temp=E.var\u count-E.distinct\u on\u rhs;
同时(温度=0;--j)
已解决=分配_值(&E,j,值);
if(solved)//不能返回任何解决方案
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_EXPRESSION_SIZE 11 + 1
#define MAX_VARIABLES 9
int variables_read[MAX_VARIABLES] = { 0 };
struct variable {
int coefficient;
int* ptr;
int side;
int canhavezero;
unsigned value_max;
};
typedef struct variable Variable;
struct equation {
Variable* variables[9]; // max
unsigned distinct_on_rhs;
unsigned var_count;
};
typedef struct equation Equation;
int int_pow(int n, int k) {
int res = 1;
for(int i = 0; i < k; ++i)
res *= n;
return res;
}
void AddVariable(Equation* E, Variable* V) {
E->variables[E->var_count++] = V;
}
int IsImpossible(char* expression) {
// if all letters are same or end letters are same, no solution
if(
(expression[0] == expression[4] && expression[0] == expression[8]) ||
(!strncmp(expression, expression + 4, 3) && !strncmp(expression, expression + 8, 3))
)
return 1;
return 0;
}
int assign_value(Equation* E, int pos, int* values) {
if(!E->variables[pos]->value_count) {
if(pos < 0)
return 2;
// if no possible values left, reset this, but take one value count from the closest variable
E->variables[pos - 1]->value_count--;
E->variables[pos]->value_count = E->variables[pos]->value_max;
return 0;
}
int i;
for(i = 9; i >= 0 && values[i] == -1; --i)
printf("Assigning %d to %c\n", E->variables[pos]->value_set[E->variables[pos]->value_count - 1], 'A' + (E->variables[pos]->ptr - E->variables[0]->ptr));
*(E->variables[pos]->ptr) = values[i];
values[i] = -1; // we have unique numbers
return 0;
}
int isSolved(Equation E) {
int sum = 0, coeff = 0;
printf("Trying...\n");
for(int i = 0; i < E.var_count; ++i) {
coeff = E.variables[i]->coefficient * (*E.variables[i]->ptr);
printf("%d ", *E.variables[i]->ptr);
if(E.variables[i]->side)
coeff *= -1;
sum += coeff;
}
printf("\nSum was %d\n", sum);
return !sum;
}
char* evaluate(char* expression) {
char* res;
// check for impossible cases first
if(IsImpossible(expression)) {
res = (char *) malloc(sizeof(char) * strlen("No Solution!"));
strcpy(res, "No Solution!");
return res;
}
res = (char *) malloc(sizeof(char) * MAX_EXPRESSION_SIZE);
// now try to find solutions, first describe the given characters as equations
Equation E;
E.var_count = 0;
E.distinct_on_rhs = 0;
int side_mode = 0, powcounter = 0;
int a = -1, b = -1, c = -1, d = -1, e = -1, f = -1, g = -1, h = -1, i = -1;
int* max_variables[MAX_VARIABLES] = { &a, &b, &c, &d, &e, &f, &g, &h, &i };
for(int j = 0; j < MAX_EXPRESSION_SIZE - 1; ++j) {
if(expression[j] == '+')
continue;
if(expression[j] == '=') {
side_mode = 1;
continue;
}
Variable* V = (Variable *) malloc(sizeof(Variable));
// we know we always get 3 digit numbers but we can easily change if we need to
V->coefficient = int_pow(10, 2 - (powcounter % 3));
V->ptr = max_variables[expression[j] - 'A'];
V->side = side_mode;
E.distinct_on_rhs += side_mode && !variables_read[expression[j] - 'A'];
if(!(powcounter % 3)) { // beginning of a number
V->value_count = 9;
V->value_max = 9;
V->canhavezero = 0;
}
else {
V->value_count = 10;
V->value_max = 10;
V->canhavezero = 1;
}
AddVariable(&E, V);
variables_read[expression[j] - 'A'] = 1;
++powcounter;
}
for(int j = 0; j < E.var_count; ++j)
printf("%d %c %d\n", E.variables[j]->coefficient, 'A' + (E.variables[j]->ptr - max_variables[0]), E.variables[j]->side);
// we got a representaion of the equation, now try to solve it
int solved = 0;
// O(9^N), where N is number of distinct variables.
// An optimization we can do is, we first assign possible max values to rhs number, then go down. We need max number.
printf("Distincts: %d\n", E.distinct_on_rhs);
do {
// try to assign values to all variables and try if it solves the equation
// but first try to assign rhs as max as possible
int values[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int temp = E.var_count - E.distinct_on_rhs;
while(temp < E.var_count) {
solved = assign_value(&E, temp, values);
++temp;
}
for(int j = E.var_count - 1 - E.distinct_on_rhs; j >= 0; --j)
solved = assign_value(&E, j, values);
if(solved) // can return no solution
break;
printf("Solving...\n");
solved = isSolved(E);
system("PAUSE");
} while(!solved);
if(solved == 2) {
res = (char *) malloc(sizeof(char) * strlen("No Solution!"));
strcpy(res, "No Solution!");
}
else {
}
return res;
}
int main() {
char expression[MAX_EXPRESSION_SIZE] = { 0 };
do {
printf("Enter the formula: ");
scanf("%s", expression);
char* res = evaluate(expression);
printf("%s\n", res);
free(res);
} while(expression[0] != '-');
return 0;
}
unsigned long long count = 0;
unsigned long long sol = 0;
void evaluate(int object[]) {
count++;
int ABC = object[0] * 100 + object[1] * 10 + object[2];
int DEF = object[3] * 100 + object[4] * 10 + object[5];
int GHI = object[6] * 100 + object[7] * 10 + object[8];
if (ABC + DEF == GHI) {
printf("%4llu %03d + %03d = %03d\n", ++sol, ABC,DEF,GHI);
}
}
void form_combos(int pool[], size_t pool_count, int object[],
size_t object_count, size_t object_count_max) {
if (object_count >= object_count_max) {
evaluate(object);
return;
}
assert(pool_count > 0);
int *pool_end = pool + pool_count - 1;
for (size_t p = 0; p < pool_count; p++) {
int sample = pool[p]; // take one out
pool[p] = *pool_end; // replace it with the end
object[object_count] = sample;
form_combos(pool, pool_count - 1, object, object_count + 1,
object_count_max);
pool[p] = sample; // restore pool item
}
}
int main() {
int pool[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
size_t pool_size = sizeof pool / sizeof pool[0];
#define object_count 9
int object[object_count];
form_combos(pool, pool_size, object, 0, object_count);
printf("Evaluate() iterations %llu\n", count);
}
1 091 + 762 = 853
2 091 + 763 = 854
3 091 + 735 = 826
...
1726 874 + 061 = 935
1727 875 + 046 = 921
1728 876 + 045 = 921
Evaluate() iterations 3628800
ABC*ABC + DEF*DEF == GHI*GHI
if (ABC*ABC + DEF*DEF == GHI*GHI) {
printf("%4llu sqr(%03d) + sqr(%03d) = sqr(%03d)\n", ++sol, ABC,DEF,GHI);
}
1 sqr(534) + sqr(712) = sqr(890)
2 sqr(546) + sqr(728) = sqr(910)
3 sqr(712) + sqr(534) = sqr(890)
4 sqr(728) + sqr(546) = sqr(910)
Evaluate() iterations 3628800
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DIGITS 10
#define MAX_VARIABLES 9
#define MAX_EXPRESSION_SIZE 11
int IsImpossible(char* expression) {
// if all letters are same or end letters are same, no solution
if(
(expression[0] == expression[4] && expression[0] == expression[8]) ||
(!strncmp(expression, expression + 4, 3) && !strncmp(expression, expression + 8, 3))
)
return 1;
return 0;
}
int ArePointersAssigned(int*** pointers) {
for(int i = 0; i < MAX_VARIABLES; ++i) {
if(**pointers[i] == -1)
return 0;
}
return 1;
}
int evaluate(int*** pointers) {
int ABC = *(*pointers[0]) * 100 + *(*pointers[1]) * 10 + *(*pointers[2]);
int DEF = *(*pointers[3]) * 100 + *(*pointers[4]) * 10 + *(*pointers[5]);
int GHI = *(*pointers[6]) * 100 + *(*pointers[7]) * 10 + *(*pointers[8]);
if (ABC + DEF == GHI) { // since we use dfs, if this is a solution simply return it
//printf("%d + %d = %d\n", ABC, DEF, GHI);
return 1;
}
return 0;
}
// use the solved pointer to escape recursion early
// check_end checks if we reached 6 for the 2nd time, if it's first time we ignore (because it's start state)
void form_combos(int pool[], int pool_count, int object_count, int*** pointers, int* solved) {
if(object_count == MAX_DIGITS - 1)
object_count = 0;
if(*solved) // if a branch solved this, escape recursion
return;
if (ArePointersAssigned(pointers)) { // that means we got a full equation set
*solved = evaluate(pointers);
if(*solved)
return;
}
int *pool_end = pool + pool_count - 1;
for (int p = pool_count - 1; p >= 0 && !*solved; p--) {
int sample = pool[p]; // take one out
pool[p] = *pool_end; // replace it with the end
int temp = **pointers[object_count];
if(**pointers[object_count] == -1)
**pointers[object_count] = sample;
form_combos(pool, pool_count - 1, object_count + 1, pointers, solved);
pool[p] = sample; // restore pool item
if(!*solved)
**pointers[object_count] = temp;
}
}
int main() {
char expression[MAX_EXPRESSION_SIZE] = { 0 };
printf("Enter the formula: ");
scanf("%s", expression);
while(expression[0] != '-') {
if(IsImpossible(expression))
printf("No solution!\n");
else {
int digits[MAX_DIGITS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int object[MAX_VARIABLES] = { -1, -1, -1, -1, -1, -1, -1, -1, -1 }; // stack for dfs
int *A = &object[0], *B = &object[1], *C = &object[2],
*D = &object[3], *E = &object[4], *F = &object[5],
*G = &object[6], *H = &object[7], *I = &object[8];
// set same pointers
int** pointers[MAX_VARIABLES] = { &A, &B, &C, &D, &E, &F, &G, &H, &I };
// analyze the equation
int var = 0;
for(int p = 0; p < MAX_EXPRESSION_SIZE; ++p) {
if(expression[p] >= 'A' && expression[p] <= 'I') {
*pointers[var++] = &object[expression[p] - 'A']; // link same pointers
}
}
int solved = 0, check_end = 0;
form_combos(digits, MAX_DIGITS, MAX_DIGITS - 4, pointers, &solved);
if(!solved) // it can be unsolvable still
printf("No solution!\n");
else
printf("%d%d%d + %d%d%d = %d%d%d\n", *A, *B, *C, *D, *E, *F, *G, *H, *I);
}
printf("Enter the formula: ");
scanf("%s", expression);
}
return 0;
}