Hello Paul!
On Tuesday, June 16, 2015 at 3:12:30 PM UTC-4, Paul wrote:
> I tried the problem of generating solutions like 123 - 45 - 67 + 89 = 100. The point is that we get 100 and we use the digits from 1 to 9 in consecutive order.
> My code is really ugly, and it also took me ages to do. Any insights on how I can improve it? The problem is stated more accurately in the initial comments.
> Many thanks for your help.
I have some thoughts, but take them with a grain of
salt. There are generally lots of different ways of
doing things.
There are also style preferences for how much generality,
abstraction, and hewing to prescriptive "good practices"
one wants to deal with.
> /*Problem 5
> Write a program that outputs all possibilities to put + or - or nothing between the numbers 1, 2, ..., 9 (in this order)
> such that the result is always 100. For example: 1 + 2 + 34 - 5 + 67 - 8 + 9 = 100.*/
>
> // First a utility function that inserts + and - into a vector of numbers to get a result
There is a question of what level of granularity one wants
for helper functions for a problem like this. You only call
insertSigns once in your code. If it were me, I might not
package a code fragment like this in a separate function.
(But that's just me.)
> int insertSigns (const std::vector<int>& numbers, const std::string& plusesAndMinuses)
> ...
I think you can simplify things (get rid of things like
concatenate and insertSigns and so on) if you organize
your problem as follows:
Recognize that there are three ways of linking neighboring
digits together: a plus sign, a minus sign, or concatenate
the digits together to form a multi-digit number.
Thus, maybe
enum Operation { concat, plus, minus };
> ...
>
> // Generate all combinations of plus/minus signs of a given length. Use recursion
First, you have stated a specific problem (single digits,
1 through 9, in order), and you haven't stated a generalized
version of the problem. I would therefore write specific
code -- I would bake the specifics of the problem into my
data and algorithm -- rather than write more general helper
functions. If you write a more general function, you (or
at least I) can't say whether it's right or wrong, because
you haven't set forth the more general specification that
your function should satisfy.
So I might use the following data structure:
const int nOperations = 8;
// there are eight concat's, '+'s, or '-'s inserted
// between 9 digits.
Operation operations[nOperations];
I would lean against recursion, and just use a simple
loop. There are 3^8 = 6561 choices for how you insert
concat, '+', or '-' between the 9 digits. (That is, the
data structure operations can take on 3^8 distinct values.)
> std::vector<std::string> plusesAndMinuses(int n)
> ...
> // Generate all vectors of numbers that can arise from concatenations in a list of numbers
> // Numbers can only be concatenated with their neighbours. Use recursion
> std::vector<std::vector<int>> concatenation (const std::vector<int>& numbers, int base = 10)
(Again, without a more general problem having been stated,
I would elect not to support the generality of having a
base other than 10.)
Again, I would use a loop rather than recursion. Also, if
you use an array (or vector, etc) of Operations as your
primary data structure, the loop where you generate the
pluses and minuses and the (implicit) loop where you (implicitly)
generate your concatenations can be one and the same.
> ...
Anyway, just some thoughts.
Good luck.
K. Frank