I am trying to figure out why my function for dilating an image doesn't produce the correct output.
My goal is to turn something like this:
.........
.........
....x....
.........
.........
into this:
.........
....x....
...xxx...
....x....
.........
for each cycle of dilation.
I haven't thought of it but I also need to to the reverse for the erosion.
This is what I've come up with so far (the program takes in input from the user in the command line using argv) :
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>
//look up line by line parsing
using namespace std;
void replacee(vector<vector<char>> &vec, char oldd, char neww)
{
for (vector<char> &v : vec) // reference to innver vector
{
replace(v.begin(), v.end(), oldd, neww); // standard library
algorithm
}
}
void dialationn(vector<vector<char>> & vec, char suspect)
{
for (int i = 0; i < vec.size(); i ++) {
for (int j = 0; j < vec[i].size(); j++) {
if (vec[i][j] == suspect) {
if (i > 0) {
vec[i-1][j] = suspect;
}
if (j > 0) {
vec[i][j-1] = suspect;
}
if (i + 1<vec.size()) {
vec[i+1][j] = suspect;
}
if (j + 1<vec[i].size()) {
vec[i][j+1] = suspect;
}
}
}
}
}
int main(int argc, char* argv[]) {
fstream fin; char ch;
string name (argv[1]); //File Name.
vector<vector<char>> data;
// 2D Vector.
vector<char> temp;
// Temporary vector to be pushed
// into vec, since its a vector of vectors.
fin.open(name.c_str(),ios::in);
// Assume name as an arbitrary file.
string argument2 (argv[2]);
string argument3 (argv[3]);
string argument4 (argv[4]);
while(fin)
{
ch = fin.get();
if(ch!='\n') {
temp.push_back(ch);
}
else
{
data.push_back(temp);
temp.clear();
}
}
if (argument2 == "replace") {
replacee(data, argument3[0], argument4[0]);
for (int i = 0; i < data.size(); i ++) {
for (int j = 0; j < data[i].size(); j++) {
cout << data[i][j];
}
cout << endl;
}
} else if (argument2 == "dialate") {
dialationn(data, argument3[0]);
for (int i = 0; i < data.size(); i ++) {
for (int j = 0; j < data[i].size(); j++) {
cout << data[i][j];
}
cout << endl;
}
}
fin.close();
}
the dialationn function I've implemented so far uses a double for loop to cycle through the 2d array, and when it finds the character that is supposed to be dilated, it checks if a border is near by and sets the coordinate accordingly.
Besides the input parsing issue discussed in the comments to the question, the dilation function proposed by OP doesn't work because it modifies the input image, rather than writing to a new output image. When modifying the input, the result of the dilation for subsequent pixels will be affected.
Correct would be:
void dialationn(vector<vector<char>> & vec, char suspect)
{
vector<vector<char>> out(vec.size(), vector<char>(vec[0].size(), 0))
for (int i = 0; i < vec.size(); i ++) {
for (int j = 0; j < vec[i].size(); j++) {
if (vec[i][j] == suspect) {
if (i > 0) {
out[i-1][j] = suspect;
}
if (j > 0) {
out[i][j-1] = suspect;
}
if (i + 1<vec.size()) {
out[i+1][j] = suspect;
}
if (j + 1<vec[i].size()) {
out[i][j+1] = suspect;
}
}
}
}
swap(out, vec);
}
Related
The code gets an exception of type out of range and i don't know why. It seems to work when i debug it, teh string is converted to what i want it to be.
First time on stack overflow btw:)
#include <iostream>
using namespace std;
string s;
string alpha = "abcdefghijklmnopqrstuvwxyz";
string crypto(string& s);
int main()
{
cin >> s;
cout << crypto(s);
return 0;
}
string crypto(string& s)
{
size_t i = 0;
while (i < s.length()) {
for (size_t j = 0; j < alpha.length(); j++) {
if (s.at(i) == alpha.at(j)) {
s.at(i) = alpha.at(alpha.length() - 1 - j);
++i;
}
}
}
return s;
}
Think about the case: if s.length() < alpha.length().
The problem was the i++ at the wrong place. You should format your code better, then this is much easier to spot.
Also avoid non-constant global variables and using namespace std:
#include <iostream>
#include <string> //Include the headers you use
const std::string alpha="abcdefghijklmnopqrstuvwxyz";
void crypto(std::string &s);
int main(){
std::string s;
crypto(s);
std::cout<<s;
return 0;
}
void crypto(std::string &s) //If you take the string by reference, it is changed, so you do not have to return it
{
for(std::size_t i = 0; i < s.length(); ++i) { //The for loop avoids the mistake completely
for(size_t j=0; j < alpha.length(); ++j){
if(s.at(i)==alpha.at(j)){
s.at(i)=alpha.at(alpha.length()-1-j);
}
}
}
}
To not solve your problem completely, there is still a bug in the code, that was also in yours. Try to find the error yourself.
The i++ was not put at the right place.
Moreover, there is another issue in the code: once an element has been replaced, you must leave the inner loop immediately (break). If not, you can have a -> z -> a in the same loop.
Input
abcyz
Output
zyxba
abcyz
#include <iostream>
#include <string>
std::string crypto(std::string& s) {
const std::string alpha = "abcdefghijklmnopqrstuvwxyz";
for (size_t i = 0; i < s.length(); ++i) {
for (size_t j = 0; j < alpha.length(); j++) {
if (s.at(i) == alpha.at(j)) {
s.at(i) = alpha.at(alpha.length() - 1 - j);
break;
}
}
}
return s;
}
int main() {
std::string s;
std::cin >> s;
std::cout << crypto(s) << std::endl;
std::cout << crypto(s) << std::endl;
return 0;
}
The inner loop of the crypto function can increment i past the end of the string. There's no test to stop it.
You could avoid this by breaking out of the loop when a letter is changed (that's more correct and potentially faster). That then means you should increment i outside the inner loop which means the outer loop can be a for loop as well.
string crypto(string &s) {
for (size_t i = 0; i < s.length(); ++i) {
for (size_t j = 0; j < alpha.length(); ++j) {
if (s.at(i) == alpha.at(j)) {
s.at(i) = alpha.at(alpha.length() - 1 - j);
break;
}
}
}
return s;
}
This question already has an answer here:
Clion exit code -1073741571 (0xC00000FD)
(1 answer)
Closed 2 years ago.
The c++ code below works fine for some inputs, but it is stuck at test 9 (number of inputs here is 6000) where it gives me this message "Process returned -1073741571 (0xC00000FD)".
This code reads information for n babies (their gender and name). Next it counts the appearances of each name then sorts the list of structures according to the appearances. Finally, it removes the duplicates and prints the top m female names and top m male names.
What does this error mean and what do I need to change to eliminate this error?
#include <iostream>
#include <fstream>
#include <algorithm>
#include <string.h>
using namespace std;
ifstream fin("input.txt");
struct baby
{
string gender,name;
int cnt;
};
bool cmp(baby a,baby b)
{
if (a.cnt>b.cnt)
return true;
else if (a.cnt==b.cnt && a.name<b.name)
return true;
return false;
}
int howmany(baby babies[],int n,int i)
{
int cnt=0;
for (int j=0; j<n; j++)
{
if (babies[i].name==babies[j].name && babies[i].gender==babies[j].gender)
{
cnt++;
}
}
return cnt;
}
void getData(baby babies[],int n)
{
for (int i=0; i<n; i++)
{
fin>>babies[i].gender>>babies[i].name;
}
}
int removeDuplicates(baby babies[],int n)
{
int j=0;
for (int i=0; i<n-1; i++)
{
if (babies[i].name!=babies[i+1].name)
babies[j++]=babies[i];
}
babies[j++]=babies[n-1];
return j;
}
int main()
{
int n,i,top,j;
fin>>n>>top;
baby babies[50000];
getData(babies,n);
for (i=0; i<n; i++)
{
babies[i].cnt=howmany(babies,n,i);
}
sort(babies,babies+n,cmp);
j=removeDuplicates(babies,n);
int cnt=0;
for (int i=0; i<j; i++)
{
if (cnt<top)
{
if (babies[i].gender=="F")
{
cout<<babies[i].name<<" ";
cnt++;
}
}
}
cout<<endl;
cnt=0;
for (int i=0; i<j; i++)
{
if (cnt<top)
{
if (babies[i].gender=="M")
{
cout<<babies[i].name<<" ";
cnt++;
}
}
}
return 0;
}
As you can see in Window's NT status reference, error code 0xC00000FD means stack overflow (usually caused by infinite recursion). In your case, it seems that you simply allocate a far too large array on the stack (line 57, baby babies[50000];), which is an array of size 50000*20=1000000. The simplest solution will be a dynamic allocation
baby* babies = new baby[50000];
// Your code here
delete[] babies;
A better solution would be to use std::vector which is a dynamic array that can grow and shrink. The simplest thing to do is to take a vector of size 50000, this way:
#include <vector>
...
std::vector<baby> babies(50000);
However, this is a poor solution as your pre-allocate 50000 elements even though you probably need much much less, and a better solution would be to add an element on-demand, using .push_back(element) method, or in your case, allocate n elements to the vector (impossible in a stack-allocated array).
I added your code with some modifications of mine:
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
ifstream fin("input.txt");
struct baby
{
string gender;
string name;
int cnt = 0;
};
bool cmp(const baby& a, const baby& b)
{
if (a.cnt > b.cnt) {
return true;
}
return a.cnt == b.cnt && a.name < b.name;
}
bool are_equal(const baby& lhs, const baby& rhs)
{
return lhs.gender == rhs.gender && lhs.name == rhs.name;
}
int howmany(const std::vector<baby>& babies, int i)
{
int cnt = 0;
for (int j = 0; j < babies.size(); j++)
{
if (babies[i].name == babies[j].name && babies[i].gender == babies[j].gender)
{
cnt++;
}
}
return cnt;
}
void getData(std::vector<baby>& babies)
{
for (int i = 0; i < babies.size(); i++)
{
fin >> babies[i].gender >> babies[i].name;
}
}
int removeDuplicates(std::vector<baby>& babies)
{
int j = 0;
for (int i = 0; i < babies.size() - 1; i++)
{
if (babies[i].name != babies[i + 1].name) {
babies[j++] = babies[i];
}
}
babies[j++] = babies.back();
return j;
}
void remove_duplicates_improved(std::vector<baby>& babies)
{
babies.erase(babies.begin(), std::unique(babies.begin(), babies.end(), are_equal));
}
int main()
{
int n;
int top;
fin >> n >> top;
std::vector<baby> babies(n);
getData(babies);
for (int i = 0; i < n; i++)
{
babies[i].cnt = howmany(babies, i);
}
sort(babies.begin(), babies.begin() + n, cmp);
remove_duplicates_improved(babies);
int cnt = 0;
for (int i = 0; i < babies.size(); i++)
{
if (cnt < top)
{
if (babies[i].gender == "F")
{
cout << babies[i].name << " ";
cnt++;
}
}
}
cout << endl;
cnt = 0;
for (int i = 0; i < babies.size(); i++)
{
if (cnt < top)
{
if (babies[i].gender == "M")
{
cout << babies[i].name << " ";
cnt++;
}
}
}
return 0;
}
Good luck
I have written a program for an assignment that cracks passwords using a dictionary attack and am trying to speed it up using Open MPI but my Open MPI version is slower and I am not sure why or what I am not understanding. The encrypted passwords are generated using a salt and a string passed into the unix function 'crypt.'
From what I have learned from looking at my class lecture notes, this is what I have come up with.
main.cc:
//****************************************************
// File: main.cc
// Author: Jordan Ward
// Purpose: Crack passwords in the form word+number
// or number+word where number can be at most
// three digits long using
// Open MPI to make it more efficient.
//*****************************************************
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <unistd.h>
#include <mpi.h>
using namespace std;
// Builds the list of encrypted passwords,
// list of dictionary words, and list of salts.
void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
vector<string> &salts);
// Builds the list of possible guesses.
void build_guesses(vector<string> &guesses, vector<string> &words);
// Tries each of the salts with each of
// the strings in the list of guesses to see
// if they match the ecrypted passwords.
void crack(string pass, vector<string> &salts, vector<string> &guesses);
// Broadcasts the vectors to all other processes.
void broadcast_receive(vector<string> &encPass, vector<string> &words,
vector<string> &salts, vector<string> &guesses);
// Converts a vector of strings to a vector of chars
vector<char> convert(vector<string> &strings);
int main(int argc, char *argv[]) {
vector<string> encPass;
vector<string> words;
vector<string> salts;
vector<string> guesses;
int numProcesses;
int procNum;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numProcesses); // Get the number of processes
MPI_Comm_rank(MPI_COMM_WORLD, &procNum); // Get the process number
if(procNum == 0) {
file_IO(argc, argv, encPass, words, salts);
build_guesses(guesses, words);
}
broadcast_receive(encPass, words, salts, guesses, numProcesses, procNum);
if(procNum != 0) {
for(size_t i = 0; i < encPass.size(); i++) {
if(i % procNum == 0) {
size_t del = encPass[i].rfind("$"); // Finds the last "$" in the string
string pass = encPass[i].substr(del); // Pass is a substring starting at the last "$"
crack(pass, salts, guesses);
}
}
}
MPI_Finalize();
return 0;
}
void file_IO(int argc, char *argv[], vector<string> &encPass, vector<string> &words,
vector<string> &salts) {
if(argc < 3) {
cout << "One or more files were not specified." << endl;
cout << "Correct format is 'mpiexec a.out file1 file2'" << endl;
exit(1);
}
ifstream secretPass(argv[1]);
string singlePass;
while(getline(secretPass, singlePass)) {
encPass.push_back(singlePass);
}
secretPass.close();
ifstream dictionary(argv[2]);
string word;
while(getline(dictionary, word)) {
words.push_back(word);
}
dictionary.close();
ifstream salt("salts");
string s;
while(getline(salt, s)) {
salts.push_back(s);
}
salt.close();
}
void build_guesses(vector<string> &guesses, vector<string> &words) {
//one word and one number
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
guesses.push_back(words[i] + to_string(j));
}
}
//one number and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < words.size(); j++) {
guesses.push_back(to_string(i) + words[j]);
}
}
//one word and two numbers
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
guesses.push_back(words[i] + to_string(j) + to_string(x));
}
}
}
//two numbers and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < words.size(); x++) {
guesses.push_back(to_string(i) + to_string(j) + words[x]);
}
}
}
//one word and three numbers
for(size_t i = 0; i < words.size(); i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
for(size_t y = 0; y < 10; y++) {
guesses.push_back(words[i] + to_string(j) + to_string(x) + to_string(y));
}
}
}
}
//three numbers and one word
for(size_t i = 0; i < 10; i++) {
for(size_t j = 0; j < 10; j++) {
for(size_t x = 0; x < 10; x++) {
for(size_t y = 0; y < words.size(); y++) {
guesses.push_back(to_string(i) + to_string(j) + to_string(x) + words[y]);
}
}
}
}
}
void crack(string pass, vector<string> &salts, vector<string> &guesses) {
for(size_t i = 0; i < salts.size(); i++) {
for(size_t j = 0; j < guesses.size(); j++) {
string ep = crypt(guesses[j].c_str(), salts[i].c_str());
if(ep.compare(salts[i] + pass) == 0) {
cout << "Password: " + guesses[j] << endl;
}
}
}
cout << "Password not found" << endl;
}
void broadcast_receive(vector<string> &encPass, vector<string> &words,
vector<string> &salts, vector<string> &guesses) {
int buffer[5];
buffer[0] = encPass.size();
buffer[1] = words.size();
buffer[2] = salts.size();
buffer[3] = guesses.size();
MPI_Bcast(buffer, 4, MPI_INT, 0, MPI_COMM_WORLD);
encPass.resize(buffer[0]);
words.resize(buffer[1]);
salts.resize(buffer[2]);
guesses.resize(buffer[3]);
vector<char> ep = convert(encPass);
vector<char> w = convert(words);
vector<char> s = convert(salts);
vector<char> g = convert(guesses);
MPI_Bcast(ep.data(), ep.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(w.data(), w.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(s.data(), s.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
MPI_Bcast(g.data(), g.size(), MPI_CHAR, 0, MPI_COMM_WORLD);
}
vector<char> convert(vector<string> &strings) {
vector<char> cstrings;
cstrings.reserve(strings.size());
for(string s : strings) {
for(size_t i = 0; i < strlen(s.c_str()); i++) {
cstrings.push_back(s.c_str()[i]);
}
}
return cstrings;
}
My thought process is:
If process number is 0, read in the files and build the vectors with strings from the files and then build the list of guesses.
Else, receive all the lists and go through each encrypted password and see if any of the salts combined with any of the guesses matches the encrypted password.
What am I not doing correctly or not understanding that is making this slower than the original without the Open MPI code? Original code would just be the same file without the broadcast_receive and convert functions and obviously without the MPI calls in the main function.
I am compiling with mpic++ -std=c++11 -Wall main.cc -lcrypt and then running with mpiexec a.out enc_passwords words where enc_passwords is a small file with some encrypted passwords generated from the crypt function and words is a small list of words to build the guesses with.
Regarding your first question (why isn't MPI "faster"?), you need to ask two questions:
Q: Is the work actually being partitioned to multiple processors, in parallel?
Q: Does the overhead of message passing exceed the actual work you're trying to parallelize?
This should help with both questions:
OpenMPI FAQ: Performance Tools
Regarding your follow-on comment, "...but for some reason it is throwing a ton of errors.": please provide an MCVE. Or simply revert back to the "working" code.
I am currently trying to separate a string by the number 2 and pushing the sub characters that i get into a 2d vector, the problem is that every time I try, I get a segmentation fault when I try to push the second row of characters in the vector. After trying a few things, I think the problem lies in the vector "some" after I clear the content of the vector. It seems to me that after the clearing, I am no longer able to push values into the vector. I hope that somebody has any suggestions because I am stuck.
std::string str = "11121112111";
std::vector<int> some;
std::vector<std::vector<int> > somemore;
for (unsigned int i = 0; i < str.length(); i++)
{
if (str[i] == '2')
{
somemore.push_back(some);
some.clear();
}
else
{
some.push_back(1);
}
}
for (unsigned int i = 0; i <= 3; i++)
{
for (unsigned int j = 0; j <= 3; j++)
{
std::cout << somemore[i][j] << std::endl;
}
}
With c++11 and Boost you can make a much more elegant solution, without the need for loops with an incrementing index.
#include <vector>
#include <string>
#include <iostream>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
int main()
{
std::string str = "11121112111";
std::vector<std::string> string_vector;
boost::split(string_vector, str, boost::is_any_of("2"));
std::vector<std::vector<int>> int_vector;
for (auto& s : string_vector)
int_vector.push_back(std::vector<int>(s.size(), 1));
for (auto& v : int_vector)
for (auto& i : v)
std::cout << i << std::endl;
return 0;
}
I would change the last part:
for(unsigned int i = 0; i <=3; i++)
{
for(unsigned int j = 0; j <=3; j++)
{
std::cout << somemore[i][j] << std::endl;
}
}
Into this:
for(unsigned int i = 0; i < somemore.size(); i++)
{
for(unsigned int j = 0; j < some.size(); j++)
{
std::cout << somemore[i][j] << std::endl;
}
}
It is much safer.
As I already mentioned in comments, you have two problems in your code:
You are not pushing the last some into somemore because there is no 2 at the end of str.
Your last loops are too large - You have a 3x3 matrix but you expect a 4x4 since you go from 0 to 3.
By the way, since you are only counting ones, you don't need some:
std::string str = "11121112111";
std::vector<std::vector<int>> somemore;
size_t count = 0;
for (size_t = 0; i < str.length(); i++) {
if (str[i] == '2') {
somemore.push_back(std::vector<int>(count, 1));
count = 0;
}
else {
++count;
}
}
for (size_t i = 0; i < somemore.size(); ++i) {
for (size_t j = 0; j < somemore[i].size(); ++j) {
std::cout << somemore[i][j] << std::endl;
}
}
You could also replace the last two loops with iterators, or if you have c++11 available:
for (const auto &s: somemore) {
for (const auto &v: s) {
std::cout << v << std::endl;
}
}
In this loop
for(unsigned int i = 0; i < str.length(); i++)
{
if(str[i] == '2')
{
sommore.push_back(som);
som.clear();
}
else
{
som.push_back(1);
}
}
where it is not clear whether som is the vector declared like
std::vector<int> some;
^^^^^
the last part of the string
std::string str = "11121112111";
^^^
is ignored by vector sommore. So the vector contains only two elements that corresponds to two 2(s) in the string.
As result these loops
for(unsigned int i = 0; i <=3; i++)
{
for(unsigned int j = 0; j <=3; j++)
{
std::cout << sommore[i][j] << std::endl;
}
}
that use the magic number 3 have undefined behaviour.
Even if the vector and its sub-vectors contain 3 elements even in this case conditions i <=3 and j <=3 are wrong.
You can adopt the following approach shown in this demonstratrive program
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::vector<int>> v;
std::string str = "11121112111";
for ( std::string::size_type pos = 0; ( pos = str.find_first_not_of( "2", pos ) ) != std::string::npos; )
{
auto n = str.find( "2", pos );
if ( n == std::string::npos ) n = str.size();
v.push_back( std::vector<int>( n - pos, 1 ) );
pos = n;
}
for ( const auto &row : v )
{
for ( int x : row ) std::cout << x;
std::cout << std::endl;
}
}
The program output is
111
111
111
Hello I am looking for a way to write this C++ Code in a general way, so that if a want 20 columns I will not have to write 20 for loops:
for(int i=1; i<6; i++) {
for(int j=i; j<6; j++) {
for(int k=j; k<6; k++) {
for(int m=k; m<6; m++) {
std::cout << i << j << k << m << std::endl;
}
}
}
}
It is important that my numbers follow a >= Order.
I am very grateful for any help.
This recursive function should work:
#include <iostream>
bool inc( int *indexes, int limit, int n )
{
if( ++indexes[n] < limit )
return true;
if( n == 0 ) return false;
if( inc( indexes, limit, n-1 ) ) {
indexes[n] = indexes[n-1];
return true;
}
return false;
}
int main()
{
const size_t N=3;
int indexes[N];
for( size_t i = 0; i < N; ++i ) indexes[i] = 1;
do {
for( size_t i = 0; i < N; ++i ) std::cout << indexes[i] << ' ';
std::cout << std::endl;
} while( inc( indexes, 6, N-1 ) );
return 0;
}
live example
The design here is simple. We take a std::vector each containing a dimension count and a std::vector containing a current index at each dimension.
advance advances the current bundle of dimension indexes by amt (default 1).
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
return;
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which gives us an advance function for generic n dimensional coordinates.
Next, a filter that tests the restriction you want:
bool vector_ascending( std::vector<size_t> const& v ) {
for (size_t i = 1; (i < v.size()); ++i) {
if (v[i-1] < v[i]) {
return false;
}
}
return true;
}
then a for loop that uses the above:
void print_a_lot( std::vector<size_t> counts ) {
for( std::vector<size_t> v(counts.size()); v < counts; advance(v,counts)) {
// check validity
if (!vector_ascending(v))
continue;
for (size_t x : v)
std::cout << (x+1);
std::cout << std::endl;
}
}
live example.
No recursion needed.
The downside to the above is that it generates 6^20 elements, and then filters. We don't want to make that many elements.
void advance( std::vector<size_t>& indexes, std::vector<size_t> const& counts, size_t amt=1 ) {
if (indexes.size() < counts.size())
indexes.resize(counts.size());
for (size_t i = 0; i < counts.size(); ++i ) {
indexes[i]+=amt;
if (indexes[i] < counts[i])
{
size_t min = indexes[i];
// enforce <= ordering:
for (size_t j = i+i; j < counts.size(); ++j) {
if (indexes[j]<min)
indexes[j]=min;
else
break; // other elements already follow <= transitively
}
assert(vector_ascending(indexes));
return;
}
assert(counts[i]!=0);
amt = indexes[i]/counts[i];
indexes[i] = indexes[i]%counts[i];
}
// past the end, don't advance:
indexes = counts;
}
which should do it without the vector_ascending check in the previous version. (I left the assert in to do testing).
This function works for me, but do not call it with 20 if you want it to finish.
#include <list>
#include <iostream>
std::list<std::list<int>> fun (std::list<std::list<int>> inputlist, int counter)
{
if(counter == 0)
{
return inputlist;
}
else
{
std::list<std::list<int>> outputlist;
for(std::list<int> oldlist : inputlist)
{
for(int i = 1; i<6; i++)
{
std::list<int> newlist = oldlist;
newlist.push_back(i);
outputlist.push_back(newlist);
}
}
return fun(outputlist, counter - 1);
}
}
int main()
{
std::list<int> somelist;
std::list<std::list<int>> listlist;
listlist.push_back(somelist);
std::list<std::list<int>> manynumbers = fun (listlist,5);
for (std::list<int> somenumbers : manynumbers)
{
for(int k : somenumbers)
{
std::cout<<k;
}
std::cout<<std::endl;
}
return 0;
}
Same with Processing (java) here :
void loopFunction(int targetLevel, int actualLevel, int min, int max, String prefix){
/*
targetLevel is the wanted level (20 in your case)
actualLevel starts from 1
min starts from 1
max is the max number displayed (6 in your case)
prefix starts from blank
see usage bellow (in setup function)
*/
for(int m=min; m<max; m++) {
if(targetLevel==actualLevel)
{
println(prefix+ " " + m);
}
else
{
loopFunction(targetLevel, actualLevel+1,m,max,prefix+ " " + m);
}
}
}
void setup(){
loopFunction(10,1,1,6,"");
}
Well, I am not the fastest in writing answer... when I started there was no other answer. Anyhow, here is my version:
#include <iostream>
#include <vector>
using namespace std;
class Multiindex {
public:
typedef std::vector<int> Index;
Multiindex(int dims,int size) :
dims(dims),size(size),index(Index(dims,0)){}
void next(){
int j=dims-1;
while (nextAt(j) && j >= 0){j--;}
}
Index index;
bool hasNext(){return !(index[0]==size-1);}
private:
bool nextAt(int j){
index[j] = index[j]+1;
bool overflow = (index[j]==size);
if (!overflow && j < dims-1){std::fill(index.begin() + j + 1,index.end(),index[j]);}
return overflow;
}
int dims;
int size;
};
int main() {
Multiindex m(4,6);
while (m.hasNext()){
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
m.next();
}
cout << m.index[0] << m.index[1] << m.index[2] << m.index[3] << endl;
return 0;
}