I'm trying to find all possible solutions to the 3X3 magic square.
There should be exactly 8 solutions.
My code gets them all but there are a lot of repeats. I'm having a hard time tracking the recursive steps to see why I'm getting all the repeats.
// This program finds all solutions to the magic square for a 3X3
// square where each column, row and diagonal sum is equal
#include <iostream>
using namespace std;
#define SQUARE_SIZE 9
int anyLine = 0;
int currLine = 0;
int numSolutions = 0;
// swap two values in the square.
void swap(int arr[], int idxa, int idxb)
{
int tmp = arr[idxa];
arr[idxa] = arr[idxb];
arr[idxb] = tmp;
}
void printArray(int arr[])
{
for (int i = 0; i < SQUARE_SIZE; i++)
{
cout << arr[i] << " ";
if ((i + 1) % 3 == 0)
cout << endl;
}
cout << endl;
}
// this function tests to see if we have a "good" arrangement of numbers
// i.e the sum of each row, column and diagonal is equal
bool checkArr(int arr[])
{
anyLine = arr[0] + arr[1] + arr[2];
currLine = 0;
for (int i = 0; i < SQUARE_SIZE; i++)
{
currLine += arr[i];
if ((i + 1) % 3 == 0)
{
if (currLine != anyLine)
return false;
currLine = 0;
}
}
// check vertically
for (int col = 0; col <3; col++)
{
for (int row = 0; row <3; row++)
{
currLine += arr[col + 3 * row];
}
if (currLine != anyLine)
return false;
currLine = 0;
}
// check the diagonals
if ((arr[2] + arr[4] + arr[6]) != anyLine)
return false;
if ((arr[0] + arr[4] + arr[8]) != anyLine)
return false;
return true;
}
void solve(int arr[], int pos)
{
if (pos == 8)
{
if (checkArr(arr))
{
printArray(arr);
numSolutions++;
}
} else
{
for (int i = 0; i < 9; i++)
{
if (i == pos) continue;
if (checkArr(arr))
{
printArray(arr);
numSolutions++;
}
swap(arr, pos, i);
solve(arr, pos + 1);
}
}
}
int main()
{
int arr[SQUARE_SIZE] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
solve(arr, 0);
cout << "number of solutions is: " << numSolutions << endl;
return 0;
}
Basically, you are finding all permutations of the array using a recursive permutation algorithm.
There are 4 things you need to change:
First, start your loop from pos, not 0
Second, swap elements back after recursing (backtracking)
Third, only test once you have generated each complete permutation (when pos = 8), or else you will be testing the same permutations more than once.
Fourth, swapping an element with itself (i.e. not swapping it) is a valid permutation, because the elements are allowed to stay in their original positions.
void solve(int arr[], int pos)
{
if (pos == 8)
{
if (checkArr(arr))
{
printArray(arr);
numSolutions++;
}
}
else
{
for (int i = pos ; i < 9; i++)
{
swap(arr,pos,i);
solve(arr,pos +1);
swap(arr,pos,i);
}
}
}
Demo
Your code calls printArray from two places - the base case of the recursion (i.e. when pos == 8) and in the loop before calling swap. The second call is unnecessary: you would get the same square when you reach the pos == 8 state.
This brings the number of duplicates down, but it does not eliminate them because of the way in which you generate your squares. You need to keep track of what has been printed. One way to do it is to make a set of solutions that you have found, and check it before printing the newly found solution:
set<int> seen;
int key(int arr[]) {
return arr[0]
+ 10 * arr[1]
+ 100 * arr[2]
+ 1000 * arr[3]
+ 10000 * arr[4]
+ 100000 * arr[5]
+ 1000000 * arr[6]
+ 10000000 * arr[7]
+ 100000000 * arr[8];
}
void printArray(int arr[]) {
if (!seen.insert(key(arr)).second) {
// second is set to false when a duplicate is found
return;
}
numSolutions++;
for (int i = 0; i < SQUARE_SIZE; i++) {
cout << arr[i] << " ";
if((i+1) % 3 == 0)
cout << endl;
}
cout << endl;
}
Demo.
A few things to note about the solution above:
key(int[]) converts the square to a single decimal number, so this approach is going to work only for squares composed of decimal digits. You would need a different strategy for arbitrary numbers - for example, using a set of comma-separated strings.
Counting of solutions is moved to printArray(int[]). You could drop numSolutions altogether, and use seen.size() instead; it provides the same answer.
If you don't want to actually solve this recursively for exercise purposes, I'd recommend using std::next_permutation:
void solve(int(&arr)[SQUARE_SIZE], int pos)
{
sort(std::begin(arr), std::end(arr));
do {
if (checkArr(arr)) {
numSolutions++;
printArray(arr);
}
} while (next_permutation(begin(arr), end(arr)));
}
Related
I have tried this code that I found online and it worked, but I want it to print out which number makes magic square. In this case it is 83, so instead of cout<<"Magic Square", how do I change it to show 83 instead?
Thank you in advance.
# define my_sizeof(type) ((char *)(&type+1)-(char*)(&type))
using namespace std;
// Returns true if mat[][] is magic
// square, else returns false.
bool isMagicSquare(int mat[][3])
{
int n = my_sizeof(mat)/my_sizeof(mat[0]);
// calculate the sum of
// the prime diagonal
int i=0,j=0;
// sumd1 and sumd2 are the sum of the two diagonals
int sumd1 = 0, sumd2=0;
for (i = 0; i < n; i++)
{
// (i, i) is the diagonal from top-left -> bottom-right
// (i, n - i - 1) is the diagonal from top-right -> bottom-left
sumd1 += mat[i][i];
sumd2 += mat[i][n-1-i];
}
// if the two diagonal sums are unequal then it is not a magic square
if(sumd1!=sumd2)
return false;
// For sums of Rows
for (i = 0; i < n; i++) {
int rowSum = 0, colSum = 0;
for (j = 0; j < n; j++)
{
rowSum += mat[i][j];
colSum += mat[j][i];
}
if (rowSum != colSum || colSum != sumd1)
return false;
}
return true;
}
// driver program to
// test above function
int main()
{
int mat[3][3] = {{ 1, 5, 6 },
{ 8, 2, 7 },
{ 3, 4, 9 }};
if (isMagicSquare(mat))
cout << "Magic Square";
else
cout << "Not a magic Square";
return 0;
}
As per suggested, I have tried to change it to:
int main()
{
int mat[3][3] = {{ 1, 5, 6 },
{ 8, 2, 7 },
{ 3, 4, 9 }};
if (isMagicSquare(mat))
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
cout<< mat[i][j] << ' ';
}
cout<< endl;
}
}
else
cout << "Not a magic Square";
return 0;
}
But it showed the whole array instead of the correct index in the array. I am sorry, I am somewhat new at the whole thing.
The result is showing up as:
1 5 6
8 2 7
3 4 9
Did I changed it in the wrong place? Or is there any further reading that I should read. Any helps would be appreciate.
The result that I am expecting is
83
as it is the number in the index that is the magic number.
If the given square is a magic square, that means when isMagicSquare(mat) is true, then iterate through the given square and print each of the values.
To do that, you'll have to learn how to print a 2D array.
In your case, you can do like below:
if (isMagicSquare(mat))
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
cout<< mat[i][j] << ' ';
}
cout<< endl;
}
}
Please check the below resources to learn more about 2D array:
How to print 2D Arrays in C++
Two Dimensional Array in C++
Multidimensional Arrays in C / C++
The array can hold negative numbers. I've written this code using recursion. First I'm summing the first i elements and then I'm checking for each such sum if the rest of the array (starting from i + 1) can be divided with this sum.
It works for some cases but not for others. I've noticed that it doesn't work if there's a prime somewhere.
It works if I sort the array in descending order beforehand but I don't understand why.
In this case the output is 2, while it should be 0.
#include <iostream>
const int N = 5;
int tab[N] = {1, 2, 3, 3, 4};
// returns the number of partitions with a given sum (or 0 if it can't be partitioned)
int divisions(int tab[N], int p, int sum) {
if (N < 2) return 0;
if (p == N) {
return 1;
}
int s_sum = tab[p++];
while (s_sum != sum && p < N) {
s_sum += tab[p++];
}
if (s_sum == sum) {
return divisions(tab, p, sum) + 1;
} else {
return 0;
}
}
// creates all the possible sums and returns the greatest number of partitions where each partition sums up to some sum
int compareAllDivisions(int tab[N]) {
int maxResult = 0;
for (int i = 0; i < N; ++i) {
int sum = 0;
for (int j = 0; j <= i; ++j) {
sum += tab[j];
}
int result = divisions(tab, i + 1, sum);
if (maxResult < result) {
maxResult = result;
}
}
if (maxResult >= 2) {
return maxResult;
} else {
return 0;
}
}
int main() {
std::cout << compareAllDivisions(tab) << std::endl;
return 0;
}
It is because of return value of if (s_sum == sum) part.
It should be changed like below
if (s_sum == sum) {
int ret = divisions(tab, p, sum);
if(ret == 0) return 0;
else return ret + 1;
} else {
return 0;
}
Your return value of divisions is 0 when can't make and pos number when can make.
So, let's consider when 0 returns in there. It can't make at the back, but it will return pos number!
Homework: I'm just stumped as hell. I have algorithms set up, but I have no idea how to code this
Just to be clear you do not need arrays or to pass variables by reference.
The purpose of the project is to take a problem apart and using Top-Down_Design or scratch pad method develop the algorithm.
Problem:
Examine the numbers from 2 to 10000. Output the number if it is a Dual_Prime.
I will call a DualPrime a number that is the product of two primes. Ad where the two primes are not equal . So 9 is not a dual prime. 15 is ( 3 * 5 ) .
The output has 10 numbers on each line.
My Algorithm set-up
Step 1: find prime numbers.:
bool Prime_Number(int number)
{
for (int i = 2; i <= sqrt(number); i++)
{
if (number % 1 == 0)
return false;
}
return true;
}
Step 2: store prime numbers in a array
Step 3: Multiply each array to each other
void Multiply_Prime_Numbers(int Array[], int Size)
{
for (int j = 0; j < Size- 1; j++)
{
Dual_Prime[] = Arr[j] * Arr[j + 1]
}
}
Step 4: Bubble sort
void Bubble_Sort(int Array[], int Size) // Sends largest number to the right
{
for (int i = Size - 1; i > 0; i--)
for (int j = 0; j < i; j++)
if (Array[j] > Array[j + 1])
{
int Temp = Array[j + 1];
Array[j + 1] = Array[j];
Array[j] = Temp;
}
}
Step 5: Display New Array by rows of 10
void Print_Array(int Array[], int Size)
{
for (int i = 0; i < Size; i++)
{
cout << Dual_Prime[i] << (((j % 10) == 9) ? '\n' : '\t');
}
cout << endl;
}
I haven't learned dynamic arrays yet,
Although dynamic arrays and the sieve of Eratosthenes are more preferable, I tried to write minimally fixed version of your code.
First, we define following global variables which are used in your original implementation of Multiply_Prime_Numbers.
(Please check this post.)
constexpr int DP_Size_Max = 10000;
int DP_Size = 0;
int Dual_Prime[DP_Size_Max];
Next we fix Prime_Number as follows.
The condition number%1==0 in the original code is not appropriate:
bool Prime_Number(int number)
{
if(number<=1){
return false;
}
for (int i = 2; i*i <= number; i++)
{
if (number % i == 0)
return false;
}
return true;
}
In addition, Multiply_Prime_Numbers should be implemented by double for-loops as follows:
void Multiply_Prime_Numbers(int Array[], int Size)
{
for (int i = 0; i < Size; ++i)
{
for (int j = i+1; j < Size; ++j)
{
Dual_Prime[DP_Size] = Array[i]*Array[j];
if(Dual_Prime[DP_Size] >= DP_Size_Max){
return;
}
++DP_Size;
}
}
}
Then these functions work as follows.
Here's a DEMO of this minimally fixed version.
int main()
{
int prime_numbers[DP_Size_Max];
int size = 0;
for(int j=2; j<DP_Size_Max; ++j)
{
if(Prime_Number(j)){
prime_numbers[size]=j;
++size;
}
}
Multiply_Prime_Numbers(prime_numbers, size);
Bubble_Sort(Dual_Prime, DP_Size);
for(int i=0; i<DP_Size;++i){
std::cout << Dual_Prime[i] << (((i % 10) == 9) ? '\n' : '\t');;
}
std::cout << std::endl;
return 0;
}
The Sieve of Eratosthenes is a known algorithm which speeds up the search of all the primes up to a certain number.
The OP can use it to implement the first steps of their implementation, but they can also adapt it to avoid the sorting step.
Given the list of all primes (up to half the maximum number to examine):
Create an array of bool as big as the range of numbers to be examined.
Multiply each distinct couple of primes, using two nested loops.
If the product is less than 10000 (the maximum) set the corrisponding element of the array to true. Otherwise break out the inner loop.
Once finished, traverse the array and if the value is true, print the corresponding index.
Here there's a proof of concept (implemented without the OP's assignment restrictions).
// Ex10_TwoPrimes.cpp : This file contains the 'main' function. Program execution begins and ends there.
#include "pch.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void Homework_Header(string Title);
void Do_Exercise();
void Sieve_Of_Eratosthenes(int n);
void Generate_Semi_Prime();
bool Semi_Prime(int candidate);
bool prime[5000 + 1];
int main()
{
Do_Exercise();
cin.get();
return 0;
}
void Do_Exercise()
{
int n = 5000;
Sieve_Of_Eratosthenes(n);
cout << endl;
Generate_Semi_Prime();
}
void Sieve_Of_Eratosthenes(int n)
{
// Create a boolean array "prime[0..n]" and initialize
// all entries it as true. A value in prime[i] will
// finally be false if i is Not a prime, else true.
memset(prime, true, sizeof(prime));
for (int p = 2; p*p <= n; p++)
{
// If prime[p] is not changed, then it is a prime
if (prime[p] == true)
{
// Update all multiples of p
for (int i = p * p; i <= n; i += p)
prime[i] = false;
}
}
}
bool Semi_Prime(int candidate)
{
for (int index = 2; index <= candidate / 2; index++)
{
if (prime[index])
{
if (candidate % index == 0)
{
int q = candidate / index;
if (prime[q] && q != index)
return true;
}
}
}
return false;
}
void Generate_Semi_Prime()
{
for (int i = 2; i <= 10000; i++)
if (Semi_Prime(i)) cout << i << "\t";
}
Beginner C++ student here starting to learn different ways of using arrays. I am trying to put together the program below. It's supposed to ask the user for an input of a set of numbers that will go into an array. This set of numbers may increase or decrease at any point the user wants.
For example:
1 2 3 4 9 8 7 4 5 6 10 11 12 20 19 18 17
The program is to check against that set of numbers and account for every time there is an increase or decrease. Right now the program will return "increase" or "decrease".
For example, running it against the aforementioned set of numbers it returns:
increasing
decreasing
decreasing
However, I have two problems:
I think it is not accounting for all the changes (increases and decreases) occurring in the array correctly. Unsure where I have gone wrong.
I now have to return the number of changes that occur instead of "decrease"/"increase". Meaning, in the example above it would return "3" because there is 1 true value and 2 false.
If anyone can advise I would immensely appreciate the help.
Thank you so very much!!!
#include <iostream>
using namespace std;
bool increasing(int arr[], int n);
int main()
{
int arr[20], n;
cout << "Enter a set of Increasing/Decreasing numbers (ex. 1 2 3 6 5 4 7 8 9 3 2 1)." << endl;
cout << "Press 'Enter' to see results" << endl;
while (cin >> n)
{
for (int i = 0; i <= n; i++)
{
cin >> arr[i];
}
cout << (increasing(arr, n) ? "increasing" : "decreasing") << endl;
}
return 0;
}
bool increasing(int arr[], int n)
{
int x = 0;
for (int i = 0; i < n - 1; i++)
{
if (arr[i] < arr[i + 1])
{
x++;
}
}
if (x == n - 1)
{
return true;
}
else
{
return false;
}
}
For the needs of 1. you have to call the increasing function several times. So you also need an integer advance to remember your advance.
bool increasing(int arr[], int& advance, int n);
You can then call it with (x counts the number of increasing as stated in 2.)
int advance = 0;
do {
int x = 0;
cout << (increasing(arr, advance, n, x) ? "increasing " : "decreasing ") << x << endl;
} while (advance < n-1);
You can implement it with
bool increasing(int arr[], int& advance, int n, int& x)
{ assert(advance < n-1);
x = 0;
bool doesIncrease = arr[advance] < arr[advance + 1];
bool isStable = arr[advance] == arr[advance + 1];
if (doesIncrease) {
for (int i = advance+1; i < n - 1; i++)
{
if (arr[i] < arr[i + 1])
{
x++;
}
}
}
else if (isStable) {
...
}
else { // decreasing
for (int i = advance+1; i < n - 1; i++)
{
if (arr[i] > arr[i + 1])
{
x++;
}
}
};
return doesIncrease;
}
I am trying to make a program that recieves numbers from the user, and then rearranges the from least to greatest. I am using vectors (which I just learned about), and it gives me a subscript out of range error. I am not able to find what part of the code gives me this error, so hopefully someone more knowledgeable on vector and c++ can find it:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void order(int a, int b);
void orderRev(int a, int b);
int main() {
vector<int> num;
bool going = true;
do {
cout << "\nEnter a number or type 'x' to order:" << endl;
string reply;
getline(cin, reply);
if (reply != "x") {
int a = atoi(reply.c_str());
num.push_back(a);
cout << "\nYou currently have " << num.size() << " numbers added." << endl;
}
else {
going = false;
}
} while (going);
for (int i = 0; i < num.size(); i++) {
order(num[i], num[i + 1]);
}
for (int i = num.size() - 1; i >= 0; i--) {
orderRev(num[i + 1], num[i]);
}
cout << "\nThe number you entered in order from least to greatest are: " << endl;
for (int i = 0; i < num.size(); i++) {
cout << num[i] << " ";
}
void order(int a, int b) {
if (a > b) {
int c = b;
b = a;
a = c;
}
}
void orderRev(int a, int b) {
if (a < b) {
int c = b;
b = a;
a = c;
}
}
Fix these lines to this:
// added the -1 as this will now go up to the 2nd to last element
// for `n`, and the last element for `n+1`
for (int i = 0; i < num.size() - 1; i++) {
order(num[i], num[i + 1]);
}
// changed the starting number to size -2 (for the same reasoning)
for (int i = num.size() - 2; i >= 0; i--) {
orderRev(num[i + 1], num[i]);
}
Why does this need to be this way? Think about how indices in C++ work. They are zero-indexed! That means that if you want both the element and the one in front of it, you must go up to the size of the vector minus 1. Hence, for a vector of 10 items (size 10), at i == 9 your code will work like this:
for (int i = 0; i < num.size(); i++) {
// i = 9
order(num[9], num[9+1]);// index 10 does not exist! Hence, you really need to go up to num.size() - 1!
}
Vectors index start with 0. index will be 0 to n-1 , if you use num[i + 1] it will exceed the vector size, if you don't check in loop condition.
Your code has more than one flaw. The output will be same as the input , hint: know the difference between pass by reference and pass by value and after that check some sorting algorithms.