问题
I have the following equation :
8 ? 7 ? 6 ? 5 ? 4 ? 3 ? 2 ? 1 = 36
and I need to make a C program that finds which operators ( from +, -, *, /
) go instead of ?
in order to make the equation true.
My initial thought is that I have 4*7=28
different combinations. So I started making arrays adding first all +
then reduce the number of +
by 1 and add another symbol and see if the equation is true. But I'm confused about the direction I took.
Also I haven't found anything similar in my many google searches, so this is my last resort.
Thanks!
回答1:
What a nice puzzle...
Here is my solution (which became smaller as I myself expected).
findOps.c
:
#include <assert.h>
#include <stdio.h>
/* too lazy to type this everytimes out... */
typedef unsigned int uint;
/* enumeration of all supported operators */
enum {
Add, Sub, Mul, Div
};
/* It is also used as encoding for compact storage with 2 bits. */
/* extracts operator i from ops. */
uint getOp(uint ops, uint i) { return (ops >> 2 * i) & 3; }
/* solves the equation with nValue values and (nValue - 1) ops
* and returns the result.
* This considers operator precedences appropriately.
*/
int solve(uint nValues, int values[], uint ops)
{
int sum = 0; /* accu for add, subtract */
int prod = values[0]; /* accu for multiply, divide */
for (int i = 1; i < nValues; ++i) {
int arg2 = values[i];
switch (getOp(ops, i - 1)) {
case Add:
sum += prod;
prod = arg2;
break;
case Sub:
sum += prod;
prod = -arg2;
break;
case Mul:
prod *= arg2;
break;
case Div:
prod /= arg2;
break;
}
}
sum += prod;
return sum;
}
/* pretty prints the equation out of internal representation. */
void print(uint nValues, int values[], uint ops, int result)
{
char chrOp[4] = { '+', '-', '*', '/' };
printf("%d", values[0]);
for (uint i = 1; i < nValues; ++i) {
printf(" %c %d", chrOp[getOp(ops, i - 1)], values[i]);
}
printf(" == %d\n", result);
}
/* main function */
int main()
{
/* assume some kind of input which provides the arguments and intended result */
int values[] = { 8, 7, 6, 5, 4, 3, 2, 1 };
enum { nValues = sizeof values / sizeof *values };
int result = 36;
/* check all combinations of operators */
uint opsEnd = 1 << 2 * (nValues - 1);
assert(8 * sizeof opsEnd >= 2 * (nValues - 1)); /* paranoid check whether opsEnd has enough bits */
uint ops = 0;
do {
if (solve(nValues, values, ops) == result) {
print(nValues, values, ops, result);
}
} while (++ops != opsEnd);
/* done */
return 0;
}
Test in cygwin on Windows 7:
$ gcc -std=c11 -o findOps findOps.c
$ ./findOps
8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 == 36
8 * 7 - 6 * 5 + 4 + 3 + 2 + 1 == 36
8 * 7 - 6 - 5 * 4 + 3 + 2 + 1 == 36
8 + 7 * 6 - 5 * 4 + 3 + 2 + 1 == 36
8 * 7 - 6 - 5 - 4 * 3 + 2 + 1 == 36
8 + 7 * 6 - 5 - 4 * 3 + 2 + 1 == 36
8 + 7 + 6 * 5 - 4 * 3 + 2 + 1 == 36
8 * 7 / 6 * 5 - 4 * 3 + 2 + 1 == 36
8 * 7 / 6 * 5 / 4 * 3 + 2 + 1 == 36
8 / 7 * 6 * 5 + 4 + 3 - 2 + 1 == 36
8 + 7 * 6 / 5 * 4 - 3 - 2 + 1 == 36
8 + 7 - 6 + 5 * 4 + 3 * 2 + 1 == 36
8 + 7 / 6 + 5 * 4 + 3 * 2 + 1 == 36
8 * 7 / 6 + 5 * 4 + 3 * 2 + 1 == 36
8 * 7 - 6 - 5 - 4 - 3 * 2 + 1 == 36
8 + 7 * 6 - 5 - 4 - 3 * 2 + 1 == 36
8 + 7 + 6 * 5 - 4 - 3 * 2 + 1 == 36
8 * 7 / 6 * 5 - 4 - 3 * 2 + 1 == 36
8 + 7 + 6 + 5 * 4 - 3 * 2 + 1 == 36
8 / 7 * 6 + 5 + 4 * 3 * 2 + 1 == 36
8 / 7 * 6 * 5 + 4 + 3 / 2 + 1 == 36
8 + 7 + 6 * 5 * 4 / 3 / 2 + 1 == 36
8 * 7 - 6 * 5 / 4 * 3 + 2 - 1 == 36
8 * 7 + 6 - 5 * 4 - 3 - 2 - 1 == 36
8 + 7 / 6 * 5 + 4 * 3 * 2 - 1 == 36
8 - 7 + 6 * 5 + 4 * 3 / 2 - 1 == 36
8 / 7 + 6 * 5 + 4 * 3 / 2 - 1 == 36
8 - 7 + 6 + 5 * 4 * 3 / 2 - 1 == 36
8 / 7 + 6 + 5 * 4 * 3 / 2 - 1 == 36
8 - 7 / 6 + 5 * 4 * 3 / 2 - 1 == 36
8 - 7 + 6 * 5 + 4 + 3 - 2 * 1 == 36
8 / 7 + 6 * 5 + 4 + 3 - 2 * 1 == 36
8 * 7 - 6 - 5 - 4 - 3 - 2 * 1 == 36
8 + 7 * 6 - 5 - 4 - 3 - 2 * 1 == 36
8 + 7 + 6 * 5 - 4 - 3 - 2 * 1 == 36
8 * 7 / 6 * 5 - 4 - 3 - 2 * 1 == 36
8 + 7 + 6 + 5 * 4 - 3 - 2 * 1 == 36
8 + 7 + 6 + 5 + 4 * 3 - 2 * 1 == 36
8 * 7 - 6 * 5 + 4 * 3 - 2 * 1 == 36
8 + 7 + 6 + 5 + 4 + 3 * 2 * 1 == 36
8 * 7 - 6 * 5 + 4 + 3 * 2 * 1 == 36
8 * 7 - 6 - 5 * 4 + 3 * 2 * 1 == 36
8 + 7 * 6 - 5 * 4 + 3 * 2 * 1 == 36
8 * 7 + 6 - 5 * 4 - 3 * 2 * 1 == 36
8 - 7 + 6 + 5 + 4 * 3 * 2 * 1 == 36
8 / 7 + 6 + 5 + 4 * 3 * 2 * 1 == 36
8 - 7 / 6 + 5 + 4 * 3 * 2 * 1 == 36
8 - 7 + 6 * 5 + 4 + 3 / 2 * 1 == 36
8 / 7 + 6 * 5 + 4 + 3 / 2 * 1 == 36
8 / 7 * 6 * 5 + 4 * 3 / 2 * 1 == 36
8 / 7 * 6 + 5 * 4 * 3 / 2 * 1 == 36
8 * 7 - 6 * 5 * 4 / 3 / 2 * 1 == 36
8 - 7 + 6 * 5 + 4 + 3 - 2 / 1 == 36
8 / 7 + 6 * 5 + 4 + 3 - 2 / 1 == 36
8 * 7 - 6 - 5 - 4 - 3 - 2 / 1 == 36
8 + 7 * 6 - 5 - 4 - 3 - 2 / 1 == 36
8 + 7 + 6 * 5 - 4 - 3 - 2 / 1 == 36
8 * 7 / 6 * 5 - 4 - 3 - 2 / 1 == 36
8 + 7 + 6 + 5 * 4 - 3 - 2 / 1 == 36
8 + 7 + 6 + 5 + 4 * 3 - 2 / 1 == 36
8 * 7 - 6 * 5 + 4 * 3 - 2 / 1 == 36
8 + 7 + 6 + 5 + 4 + 3 * 2 / 1 == 36
8 * 7 - 6 * 5 + 4 + 3 * 2 / 1 == 36
8 * 7 - 6 - 5 * 4 + 3 * 2 / 1 == 36
8 + 7 * 6 - 5 * 4 + 3 * 2 / 1 == 36
8 * 7 + 6 - 5 * 4 - 3 * 2 / 1 == 36
8 - 7 + 6 + 5 + 4 * 3 * 2 / 1 == 36
8 / 7 + 6 + 5 + 4 * 3 * 2 / 1 == 36
8 - 7 / 6 + 5 + 4 * 3 * 2 / 1 == 36
8 - 7 + 6 * 5 + 4 + 3 / 2 / 1 == 36
8 / 7 + 6 * 5 + 4 + 3 / 2 / 1 == 36
8 / 7 * 6 * 5 + 4 * 3 / 2 / 1 == 36
8 / 7 * 6 + 5 * 4 * 3 / 2 / 1 == 36
8 * 7 - 6 * 5 * 4 / 3 / 2 / 1 == 36
$
Live Demo on coliru
In ful trust on my coding abilities, I choosed randomly one line and checked it with the Windows calculator – it was correct.
Notes:
To iterate through all possible combinations of operators, the operators
+
,-
,*
,/
are mapped to 0 ... 3. As these four values can be stored with exactly 2 bits, the sequence of all operators is stored in oneunsigned
. This makes iteration through all possible combinations extremely easy – it's just incrementing the resp.unsigned
.To solve the equation, I remembered how ancient pocket calculators (without support of
()
) did this (with very limited resources). I didn't remember clearly (as it's decades ago somebody explained it to me) but was able to re-invent it. As there are only two possible precedences in+
,-
,*
,/
, it is fully sufficient to work with two buffers – one for the accumulated intermediate product, one for the accumulated intermediate sum.The computations are done in
int
arithmetic. That means these computations are mathematical correct with the constraint to Natural numbers and integer operations. (I didn't check for overflow/underflow/wrap-around but I've a "good feeling" for the sample numbers. According to howsolve()
works, division by 0 cannot be an issue as long as there is no0
in input.)What I left out: parsing the text into the data structures I used in my sample. I leave this as exercise...
来源:https://stackoverflow.com/questions/49918925/how-to-make-c-find-all-different-symbol-combinations-to-have-a-certain