如何解决为操作问题添加选项选择操作
我正在尝试编写一个小程序来解决倒计时问题。基本上,给定一个数字n
和一个数字向量,如果可以使用简单的操作(例如加法,div,mult和subs)构造n
,则会输出问题。
可以不用数字向量的所有元素,但是每个数字最多只能使用一次。
我要提供给程序的输入是一个带有反向修饰符号的字符串,因此我做了一个小函数来解决这种表达式。
这是我的代码:
#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 + / +
(顺序无关紧要)
阅读本内容
Edit2: 我添加了一个函数,该函数生成具有向量的所有可能选择的矩阵(具有重复项),如下所示:
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();
}
}
}
}
因此,基本上,现在的问题是,能够将所有可能的操作添加到矩阵中的每个条目中,这就是我迷路的地方。 我知道暴力破解是BAD,但是我只对这4个操作和6个值感兴趣。 我也担心组合爆炸...
解决方法
最后我想到了这个
#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,37);
}
我不会接受这个答案,因为我认为这很冗长,必须有一种更好的方法。 我只对一种解决方案感兴趣,所以复杂度降低了。
,#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],exp)){
ans.push_back(to_string(exp[index]));
ans.push_back("-");
return true;
}
}
else
if(_oprator[i]=='*'){
if(foo(stk*exp[index],exp)){
ans.push_back(to_string(exp[index]));
ans.push_back("*");
return true;
}
}
else
if(_oprator[i]=='/'){
if(foo(stk/exp[index],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],exp)){ //we are always choosing the first number
ans.push_back(to_string(exp[0]));
return true;
}
return false;
}
bool foo(int stk,vector<int>exp){
stk拥有到目前为止我们可以产生的价值。 index是exp向量的索引。 在foo内部,我们尝试将所有运算符组合在一起。
如果有任何答案,它将存储在ans中。只需反转它,它就会给出我们必须使用运算符来获得n的顺序。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。