简体   繁体   English

使用递归将所有可能的组合(带有重复)作为数组中的值

[英]All possible combinations(with repetition) as values in array using recursion

I'm trying to solve a problem in which I need to insert math operations(+/- in this case) between digits or merge them to get a requested number. 我正在尝试解决一个问题,我需要在数字之间插入数学运算(在这种情况下为+/-),或者将它们合并以获取所需的数字。

For ex.: 123456789 => 123+4-5+6-7+8-9 = 120 例如: 123456789 => 123+4-5+6-7+8-9 = 120

My concept is basically generating different combinations of operation codes in array and calculating the expression until it equals some number. 我的概念基本上是在数组中生成操作码的不同组合,然后计算表达式,直到等于某个数字。

The problem is I can't think of a way to generate every possible combination of math operations using recursion. 问题是我想不出一种使用递归生成数学运算的所有可能组合的方法。

Here's the code: 这是代码:

#include <iostream>
#include <algorithm>

using namespace std;

enum {noop,opplus,opminus};//opcodes: 0,1,2

int applyOp(int opcode,int x, int y);
int calculate(int *digits,int *opcodes, int length);
void nextCombination();

int main()
{
    int digits[9] = {1,2,3,4,5,6,7,8,9};
    int wantedNumber = 100;

    int length = sizeof(digits)/sizeof(digits[0]);

    int opcodes[length-1];//math symbols
    fill_n(opcodes,length-1,0);//init

    while(calculate(digits,opcodes,length) != wantedNumber)
    {
        //recursive combination function here
    }

    return 0;
}
int applyOp(int opcode,int x, int y)
{
    int result = x;
    switch(opcode)
    {
        case noop://merge 2 digits together
            result = x*10 + y;
            break;
        case opminus:
            result -= y;
            break;
        case opplus:
        default:
            result += y;
            break;
    }
    return result;
}
int calculate(int *digits,int *opcodes, int length)
{
    int result = digits[0];
    for(int i = 0;i < length-1; ++i)//elem count
    {
        result = applyOp(opcodes[i],result,digits[i+1]);//left to right, no priority
    }
    return result;
}

The key is backtracking. 关键是回溯。 Each level of recursion handles a single digit; 每个递归级别都处理一个数字。 in addition, you'll want to stop the recursion one you've finished. 此外,您将要停止已完成的递归操作。

The simplest way to do this is to define a Solver class, which keeps track of the global information, like the generated string so far and the running total, and make the recursive function a member. 最简单的方法是定义一个Solver类,该类跟踪全局信息(例如到目前为止生成的字符串和运行的总数),并使递归函数成为成员。 Basically something like: 基本上像这样:

class Solver
{
    std::string const input;
    int const target;

    std::string solution;
    int total;
    bool isSolved;

    void doSolve( std::string::const_iterator pos );
public:
    Solver( std::string const& input, int target )
        : input( input )
        , target( target )
    {
    }

    std::string solve()
    {
        total = 0;
        isSolved = false;
        doSolve( input.begin() );
        return isSolved
            ? solution
            : "no solution found";
    }
};

In doSolve , you'll have to first check whether you've finished ( pos == input.end() ): if so, set isSolved = total == target and return immediately; doSolve ,您必须首先检查是否已完成( pos == input.end() ):如果是,则设置isSolved = total == target并立即返回; otherwise, try the three possibilities, ( total = 10 * total + toDigit(*pos) , total += toDigit(*pos) , and total -= toDigit(*pos) ), each time saving the original total and solution , adding the necessary text to solution , and calling doSolve with the incremented pos . 否则,尝试三种可能性( total = 10 * total + toDigit(*pos)total += toDigit(*pos)total -= toDigit(*pos) ),每次保存原始的totalsolution ,添加solution所需的文本,然后用递增的pos调用doSolve On returning from the recursive call, if ! isSolved 从递归调用返回时,如果! isSolved ! isSolved , restore the previous values of total and solution , and try the next possibility. ! isSolved ,恢复totalsolution的先前值,然后尝试下一种可能性。 Return as soon as you see isSolved , or when all three possibilities have been solved. 看到isSolved或解决所有三种可能性后,立即返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM