在这种情况下,我如何循环通过所有各种可能性?

时间:2014-01-21 21:33:37

标签: c++ string integer

我看到了一个我决定尝试的编程任务,它基本上是用户输入类似“123456789 = 120”的东西,并且程序必须在不同位置插入“+”或“ - ”来制作语句真正。例如,在这种情况下,它可以做123 + 4-5 + 6-7 + 8-9 = 120.只有3 ^ 8种可能的组合,所以我认为可以蛮力它,但我不喜欢我不知道我可以进入的顺序/如何实际实现它。更具体地说,我不知道在插入'+'和' - '时我会采用什么顺序。这就是我所拥有的:

#include <iostream>
#include <cmath>

using namespace std;

int string_to_integer(string);

int main()
{
    string input, result_string;
    int result, possibilities;

    getline(cin, input);

    //remove spaces
    for(int i = 0; i < input.size(); i++)
    {
        if(input[i] == ' ')
        {
            input.erase(i, 1);
        }
    }

    result_string = input.substr(input.find('=') + 1, input.length() - input.find('='));
    result = string_to_integer(result_string);
    input.erase(input.find('='), input.length() - input.find('='));

    possibilities = pow(3, input.length() - 1);
    cout << possibilities;

}

int string_to_integer(string substring)
{
    int total = 0;
    int power = 1;

    for(int i = substring.length() - 1; i >= 0; i--)
    {
        total += (power * (substring[i] - 48));
        power *= 10;
    }

    return total;
}

3 个答案:

答案 0 :(得分:1)

基本想法:生成+-运算符的所有可能变体(包括缺少运算符的情况),然后解析字符串并获取总和。

方法:组合地,很容易证明我们可以通过将运算符(或不存在运算符)与基数为3的数字相关联来实现。因此,我们可以迭代每个8位三进制数,但不是打印0,1和2,而是在字符串中的下一个数字之前附加“+”,“ - ”或任何内容。

请注意,我们 实际上需要一个字符串;也可以直接使用数字和运算符等,即时计算结果。我只采用基于字符串的方法,因为它解释起来很简单,实现起来很简单,另外,它给了我们一些视觉反馈,这有助于理解解决方案。

现在我们已经构造了我们的字符串,我们可以解析它;最简单的解决方案是使用C标准库函数strtol()来实现此目的,它将考虑符号并返回有符号整数。因此,我们可以在一个简单的循环中对所有有符号整数求和,然后就完成了。

<强>代码:

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>

int main()
{
    const char *ops = " +-";

    // 3 ^ 8 = 6561
    for (int i = 0; i < 6561; i++) {
        // first, generate the line
        int k = i;
        std::string line = "1";
        for (int j = 0; j < 8; j++) {
            if (k % 3)
                line += ops[k % 3];

            k /= 3;
            line += (char)('2' + j);
        }

        // now parse it
        int result = 0;
        const char *s = line.c_str();
        char *p;

        while (*s) {
            int num = strtol(s, &p, 10);
            result += num;
            s = p;
        }

        // output
        std::cout << line << " = " << result << (result == 120 ? " MATCH" : "") << std::endl;
    }

    return 0;
}

<强>结果:

h2co3-macbook:~ h2co3$ ./quirk | grep MATCH
12-3-45+67+89 = 120 MATCH
1+2-34-5+67+89 = 120 MATCH
12-3+4+5+6+7+89 = 120 MATCH
1-23+4+56-7+89 = 120 MATCH
1+2+34-5+6-7+89 = 120 MATCH
123+4+5-6-7-8+9 = 120 MATCH
1+2-3+45+6+78-9 = 120 MATCH
12-3+45+67+8-9 = 120 MATCH
123+4-5+6-7+8-9 = 120 MATCH
123-4+5+6+7-8-9 = 120 MATCH
h2co3-macbook:~ h2co3$ 

答案 1 :(得分:0)

以下bool advance(string& s)函数会为您提供除{1}之外的任意长度的'+''-'' '字符串的所有组合,如果不再有,则返回false可用。

char advance(char c)
{
    switch (c)
    {
        case ' ': return '+';
        case '+': return '-';
        default: case '-': return ' ';
    }
}

bool advance(string& s)
{
    for (int i = 0; i < s.size(); ++i)
        if ((s[i] = advance(s[i])) != ' ')
            return true;

    return false;
}

你必须首先用一个只包含所需长度的空格的字符串来喂它,然后重复'前进'它。用法:

string s = "    ";
while (advance(s))
    cout << '"' << s << '"' << endl;

上面的代码将打印

"+   "
"-   "
" +  "
"++  "
"-+  "
" -  "
.
.
.
" ---"
"+---"
"----"

请注意,不会打印仅包含4个空格的“第一个”组合。

您可以将这些组合与您的lhs交叉,跳过空格,以生成表达式。

答案 2 :(得分:0)

另一个非常类似的方法, in plain C OK,在C ++中如果你真的想要那样;)并且可以更加可配置

使用相同的基数3数字技巧来枚举void,+和 - 运算符的组合。

该字符串作为一起添加的正值或负值列表处理。

另一个贡献是非常紧凑和优雅,但使用一些C技巧来缩短代码 希望这一点更加细致,尽管不那么漂亮。

#include <iostream>
#include <string>
using namespace std;

#include <string.h>
#include <math.h>

void solver (const char * str, int result)
{
    int op_max = pow(3, strlen(str)); // number of operator permutations

    // loop through all possible operator combinations
    for (int o = 0 ; o != op_max ; o++)
    {
        int res  = 0; // computed operation result
        int sign = 1; // sign of the current value

        int val = str[0]-'0'; // read 1st digit
        string litteral;      // litteral display of the current operation

        // parse remaining digits
        int op;
        for (unsigned i=1, op=o ; i != strlen (str) ; i++, op/=3)
        {
            // get current digit
            int c = str[i]-'0';

            // get current operator
            int oper = op % 3;

            // apply operator
            if (oper == 0) val = 10*val + c;
            else
            {
                // add previous value
                litteral += sign*val;
                res += sign*val;

                // store next sign
                sign = oper == 1 ? 1 : -1;

                // start a new value
                val = c;
            }
        }   

        // add last value
        litteral += sign*val;
        res += sign*val;

        // check result
        if (res == result)
        {
            cout << litteral << " = " << result << endl;
        }
    }
}

int main(void)
{
    solver ("123456789", 120);
}

注意:我使用了std::string的懒惰,虽然它们的速度非常慢。