1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
|
#include <iostream>
#include <limits>
#include <random>
#include <sstream>
#include <vector>
bool verbose = false;
constexpr auto NullValue = std::numeric_limits<int>::min();
using Problem = std::vector<int>;
using Parens = std::vector<std::pair<int,int>>;
// Convert string input to vector<int>.
Problem read(std::string str) {
std::istringstream iss(str);
int n;
iss >> n;
Problem prob;
prob.push_back(n);
for (char op; iss >> op >> n; )
prob.push_back(op == '-' ? -n : n);
return prob;
}
// Generate a random input problem in vector<int> form.
// Length is from min_size to max_size; operands are from -99 to 99 (but not 0)
Problem rnd_prob(int min_size, int max_size) {
using UID = std::uniform_int_distribution<>;
static auto rng = std::mt19937(std::random_device{}());
static UID distSize(min_size, max_size);
static UID distValuesFirst(1, 99);
static UID distValues(-98, 99);
int size = distSize(rng);
Problem prob;
prob.push_back(distValuesFirst(rng)); // first must be positive
for (int i = 1; i < size; i++) {
int n = distValues(rng);
if (n <= 0) --n; // exclude zero
prob.push_back(n);
}
return prob;
}
// Calculate value given problem and parens.
int calc(Problem& prob, Parens& parens) {
int val = 0, subval = 0, p = 0;
bool in_group = false;
for (int i = 0; i < int(prob.size()); ++i) {
if (p < int(parens.size()) && parens[p].first == i && prob[i] < 0) {
in_group = true;
subval -= prob[i];
}
else if (in_group)
subval += prob[i];
else
val += prob[i];
if (p < int(parens.size()) && parens[p].second == i) {
++p;
if (in_group) {
in_group = false;
val -= subval;
subval = 0;
}
}
}
return val;
}
// Print problem given problem and parens vectors.
void print(Problem& prob, Parens& parens, int value=NullValue) {
int p = 0;
if (p < int(parens.size()) && parens[p].first == 0)
std::cout << '(';
std::cout << prob[0];
for (int i = 1; i < int(prob.size()); ++i) {
int n = prob[i];
if (n < 0) {
std::cout << " - ";
n = -n;
}
else
std::cout << " + ";
if (p < int(parens.size()) && parens[p].first == i)
std::cout << '(';
std::cout << n;
if (p < int(parens.size()) && parens[p].second == i) {
std::cout << ')';
++p;
}
}
if (value != NullValue) std::cout << " = " << value;
std::cout << '\n';
}
// Recursive part of brute-force solver.
void brute_r(Problem& prob, Parens& parens, int &max_val,
Parens& best_parens, int start=0) {
for (int i = start; i < int(prob.size()); i++) {
if (prob[i] >= 0) continue; // don't start a group on a positive
if (i > start && prob[i-1] < 0) // don't exclude a previous negative
continue;
for (int j = i+1; j < int(prob.size()); j++) {
if (prob[j] >= 0) continue; // don't end a group on a positive
if (j<int(prob.size()-1) && prob[j+1] < 0)
continue; // if next is also negative, include it
parens.push_back(std::make_pair(i, j));
int val = calc(prob, parens);
if (verbose) print(prob, parens, val);
if (val > max_val) {
max_val = val;
best_parens = parens;
}
brute_r(prob, parens, max_val, best_parens, j+1);
parens.pop_back();
}
}
}
// Brute force solver.
int brute(Problem& prob) {
Parens parens, best_parens;
int max_val = calc(prob, parens); // value with no parens
if (verbose) print(prob, parens, max_val);
brute_r(prob, parens, max_val, best_parens);
if (verbose) std::cout << "------------------\n";
print(prob, best_parens, max_val);
return max_val;
}
#include <cstdlib> // atoi
#include <cstring> // strchr
int main(int argc, char **argv) {
int num_probs = 1, min_size = 10, max_size = 20;
bool do_prob_string = false;
if (argc > 1 && argv[1][0] == 'v' && argv[1][1] == '\0') {
verbose = true;
--argc;
++argv;
}
if (argc == 4) {
num_probs = std::atoi(argv[1]);
min_size = std::atoi(argv[2]);
max_size = std::atoi(argv[3]);
}
else if (argc == 2) {
if (std::strchr(argv[1], '+') || std::strchr(argv[1], '-'))
do_prob_string = true;
else
min_size = max_size = std::atoi(argv[1]);
}
else if (argc != 1) {
std::cerr << "Usage: brute [v] [prob_size]\n"
" brute [v] num_probs min_size max_size\n"
" brute [v] problem_string\n";
return 1;
}
for (int i = 0; i < num_probs; i++) {
Problem prob;
if (do_prob_string)
prob = read(argv[1]);
else
prob = rnd_prob(min_size, max_size);
brute(prob);
std::cout << '\n';
}
}
|