【问题标题】:Adding operations for choices for the Contdown problem [duplicate]为 Contdown 问题的选择添加操作 [重复]
【发布时间】:2021-02-12 10:26:06
【问题描述】:

我正在尝试制作一个小程序来解决倒计时问题。基本上,给定一个数字n 和一个数字向量,如果n 可以通过简单的操作(例如加法、div、mult 和 subs)来构造,则问题输出。 不使用数字向量的所有元素是可以的,但每个数字最多只能使用一次。

我试图给程序的输入是一个带有反向波兰符号的字符串,所以我做了一个小函数来解决这种表达式。

这是我的代码:

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

bool is_number(const std::string& s) {
    string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

vector<string> parseInput(const string& expression) {
    vector<string> parsedInp;
    string current = "";
    for (auto token : expression) {
        if (isdigit(token)) {
            current += token;
        }
        else if (token == ' ') {
            if (current != "") {
                parsedInp.push_back(current);
                current = "";
            }
        }
        else {
            parsedInp.push_back(string(1, token));
        }
    }
    return parsedInp;
}

double operateExpression(const vector<string>& parsedInp) {
    stack<double> expression;
    for (auto token : parsedInp) {
        if (is_number(token)) {
            expression.push(stod(token));
        }
        else {
            double op1 = expression.top();
            expression.pop();
            double op2 = expression.top();
            expression.pop();
            if (token == "+") {
                expression.push(op1 + op2);
            }           
            if (token == "-") {
                expression.push(op1 - op2);
            }           
            if (token == "*") {
                expression.push(op1 * op2);
            }           
            if (token == "/") {
                expression.push(op1 / op2);
            }
        }
    }
    return expression.top();
}


string getSolution(vector<string> inp, const int target) {
    vector<string> op = { "+", "-", "*", "/", "" };
    //TODO....
    
}


int main() {
    string expression;
    getline(cin, expression);
    vector<string> parsedInp = parseInput(expression);
    cout << operateExpression(parsedInp) << endl;
}

所以我的第一个直觉是创建向量的所有可能排列,然后尝试连接向量中的操作,但我现在面临的问题是我找不到简单的方法来做到这一点。我不能不小心将它连接起来,因为operateExpression 会失败,但我不想使用try 和catch 来解决这个问题。另外,我认为应该有更简单的方法。

基本上,问题在于我不知道为原始向量的所有子集和排列生成所有可能表达式的好方法。例如,如果我有 (2,5) 作为输入,则可能有以下表达式: 2 5 + 2 5 - 2 5 / 2 5 * (还有以5 作为第一个参数的相同操作。

对于(2,5,4): (以上所有加...) (2 5 + 4 +) (2 5 - 4 +) ... 以及上述的所有排列。

那么有没有更好的方法在这里写getSolution? 谢谢。

编辑: 输入示例:(100,4,17,9,3,2) 和 n = 37 -> 17 100 3 2 + / +(顺序无关紧要)

阅读本文

编辑2: 我添加了一个函数,该函数生成一个矩阵,其中包含向量的所有可能选择(有重复),如下所示:

void choices(const vector<int>& values, int& currentValue, vector<int>& currentSet, vector<vector<int>>& combinations) {
    if (currentSet.size() < values.size()) {
        for (auto i : values) {
            if (i != currentValue) {
                currentSet.push_back(i);
                combinations.push_back(currentSet);
                choices(values, i, currentSet, combinations);
                currentSet.pop_back();
            }
        }
    }
}

所以基本上问题现在减少到能够将所有可能的操作添加到矩阵中的这些条目中的每一个,这就是我迷失的地方。 我知道暴力破解是不好的,但我只对这 4 个操作和 6 个值感兴趣。 还有就是怕组合爆炸……

【问题讨论】:

  • 您能提供一个输入示例吗?
  • @RiccardoPetraglia 完成
  • 您可以使用std::next_permutation创建容器的所有排列。
  • @Darhuuk but std::next_permutation 不关心重复,操作可以重复
  • @Norhther 但这不是你在问题中所说的。你说你的第一直觉是创造所有的排列,但你找不到一个简单的方法来做到这一点。请用尽可能多的信息扩展您的问题。此外,重复排列不会使生成的答案出错,只会使程序变慢。目前尚不清楚这是否是一个问题。

标签: c++ algorithm c++11


【解决方案1】:
#include<iostream>
#include<vector>
#include<string>
#include<bits/stdc++.h>
using namespace std;

vector<int>vec;
vector<char>_oprator;
vector<string>ans;

bool solve(vector<int>);
bool foo(int,int,vector<int>);
void fine(){
    cout<<"fine"<<endl;
}
void display(vector<int>vec){
    cout<<endl<<"displaying"<<endl;
    for(int x: vec)
        cout<<x<<" ";
    cout<<endl;
    cout<<endl;
}
int  n;
int main(){
    _oprator.push_back('+');
    _oprator.push_back('-');
    _oprator.push_back('*');
    _oprator.push_back('/');

    int length;
    cin>>length;
    cin>>n;
    int temp;
    for(int i=0;i<length;i++){
        cin>>temp;
        vec.push_back(temp);
    }
    display(vec);
    int tot=pow(2,length)-1;
    for(int i=1;i<=tot;i++){
        vector<int>arr;
        for(int j=0;j<60;j++){
            if(i&(1<<j) && j<vec.size())
                arr.push_back(vec[j]);
        }
        //cout<<"i "<<i<<endl;
        //display(arr);
        if(solve(arr)){
            cout<<"Gotcha"<<endl;
            reverse(ans.begin(),ans.end());
            for(string s: ans){
                cout<<s<<" ";
            }
            cout<<endl;
            break;
        }
        arr.clear();
    }

    return 0;
}

bool solve(vector<int>exp){
    //cout<<"inside solve"<<endl;
    display(exp);
    if(exp.size()==0)
        return false;
    if(foo(exp[0],1,exp)){
        ans.push_back(to_string(exp[0]));
        return true;
    }
    return false;
}
bool foo(int stk,int index,vector<int>exp){
    //cout<<"ïnside foo"<<endl;
    //cout<<"index "<<index<<endl;
    //cout<<"stk "<<stk<<endl;
    if(index>=exp.size()){
        return stk==n;
    }
    for(int i=0;i<_oprator.size();i++){
        if(_oprator[i]=='+'){
            if(foo(stk+exp[index],index+1,exp)){
                ans.push_back(to_string(exp[index]));
                ans.push_back("+");
                return true;
            }
        }
        else
        if(_oprator[i]=='-'){
            if(foo(stk-exp[index],index+1,exp)){
                ans.push_back(to_string(exp[index]));
                ans.push_back("-");
                return true;
            }
        }
        else
        if(_oprator[i]=='*'){
            if(foo(stk*exp[index],index+1,exp)){
                ans.push_back(to_string(exp[index]));
                ans.push_back("*");
                return true;
            }
        }
        else
        if(_oprator[i]=='/'){
            if(foo(stk/exp[index],index+1,exp)){
                ans.push_back(to_string(exp[index]));
                ans.push_back("/");
                return true;
            }
        }
    }
    return false;

}

我们使用recursion 来确定在哪里可以使用最多一次的数字获得n。 大多数变量都是在外部声明的,所以如果我们在函数内部传递它们,它会消耗更多的内存。 display 和 fine 函数用于调试目的。如果您希望可以删除它们。

length 是存储在vec 中的数字列表 n 是我们必须生成的目标。

int tot=pow(2,length)-1;

tot 表示我们可以选择数字序列的方式总数

vector<int>arr;
for(int j=0;j<60;j++){
    if(i&(1<<j) && j<vec.size()) //checking if particular bit is set.
        arr.push_back(vec[j]);   //if its set we are adding it to list.
}
if(solve(arr)){//if solve returns true we got n 
    cout<<"Gotcha"<<endl;
    reverse(ans.begin(),ans.end());  //we have to reverse it to see the orginal ans
    for(string s: ans){
        cout<<s<<" ";
    }
     cout<<endl;
     break;
}
bool solve(vector<int>exp){
    //cout<<"inside solve"<<endl;
    display(exp);
    if(exp.size()==0)
        return false;
    if(foo(exp[0],1,exp)){     //we are always choosing the first number
        ans.push_back(to_string(exp[0]));
        return true;
    }
    return false;
}
 
bool foo(int stk,int index,vector<int>exp){

stk 拥有我们迄今为止可以产生的价值。 index 是 exp 向量的索引。 在 foo 中,我们尝试将所有运算符组合在一起。

如果有任何答案,则将其存储在 ans.只需将其反转,它就会给出我们必须使用运算符来获取 n 的顺序。

【讨论】:

  • @Norhther 您是否尝试过上述的 aproacing n 方式?它满足你的答案吗?
【解决方案2】:

我终于想到了这个

#include <iostream>
#include <stack>
#include <string>
#include <vector>
#include <algorithm>
#include <set>
using namespace std;

using uint = unsigned int;

bool is_number(const std::string& s) {
    string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}

vector<string> parseInput(const string& expression) {
    vector<string> parsedInp;
    string current = "";
    for (auto token : expression) {
        if (isdigit(token)) {
            current += token;
        }
        else if (token == ' ') {
            if (current != "") {
                parsedInp.push_back(current);
                current = "";
            }
        }
        else {
            parsedInp.push_back(string(1, token));
        }
    }
    return parsedInp;
}

bool isCorrectRPN(vector<string>& expression) {
    int ssize = 0;
    for (string token : expression) {
        if (token == "+" or token == "-" or token == "/" or token == "*") {
            ssize -= 1;
        }
        else if (token != " "){
            ssize += 1;
        }
        if (ssize < 0) return false;
    }
    return ssize == 1;
}

double operateExpression(const vector<string>& parsedInp) {
    stack<double> expression;
    for (auto token : parsedInp) {
        if (is_number(token)) {
            expression.push(stod(token));
        }
        else if (token != " ") {
            double op1 = expression.top();
            expression.pop();
            double op2 = expression.top();
            expression.pop();
            if (token == "+") {
                expression.push(op1 + op2);
            }           
            if (token == "-") {
                expression.push(op2 - op1);
            }           
            if (token == "*") {
                expression.push(op1 * op2);
            }           
            if (token == "/") {
                expression.push(op2 / op1);
            }
        }
    }
    return expression.top();
}

void printValues(const vector<string>& val) {
    for (auto a : val) {
        cout << a;
    }
    cout << endl;
}

void choices(const vector<string>& values, vector<string>& currentSet, int& nVals, bool& finished, set<int>& valuesInUse, const int N) {
    if (not finished) {
        vector<string> op = { "+", "-", "*", "/", " "};
        if (currentSet.size() and operateExpression(currentSet) == N) {
            printValues(currentSet);
            finished = true;
        }
        else if (nVals < values.size()) {
            for (uint i = 0; i < values.size(); i++) {
                if (valuesInUse.find(i) == valuesInUse.end()) {
                    valuesInUse.insert(i);
                    for (auto o : op) {
                        currentSet.push_back(values[i]);
                        currentSet.push_back(o);
                        nVals++;
                        if (isCorrectRPN(currentSet)) {
                            choices(values, currentSet, nVals, finished, valuesInUse, N);
                        }
                        nVals--;
                        currentSet.pop_back();
                        currentSet.pop_back();
                    }
                    valuesInUse.erase(i);
                }
            }
        }
    }
}


/*
bool hasSpace(const vector<string>& v) {
    return v[v.size() - 1] == " ";
}

void cleanChoices(vector<vector<string>>& m) {
    m.erase(std::remove_if(m.begin(), m.end(), hasSpace), m.end());
}*/


int main() {
    //string expression;
    //getline(cin, expression)
    const vector<string> values = { "100","4","17","9","3","2" };
    vector<string> currentSet;
    int nVals = 0;
    bool finished = false;
    set<int> valuesInUse;
    choices(values, currentSet, nVals, finished, valuesInUse, 37);
}

我不会接受这个作为答案,因为我认为这很冗长,必须有更好的方法来做到这一点。 我只对一种解决方案感兴趣,因此复杂性降低了。

【讨论】:

    猜你喜欢
    • 2012-04-10
    • 1970-01-01
    • 2013-11-28
    • 1970-01-01
    • 2016-02-18
    • 2018-12-02
    • 2016-11-28
    • 1970-01-01
    • 2010-12-17
    相关资源
    最近更新 更多