Pythagorean triple nested loops missunderstanding - c++

Greetings and regards;
I was trying to find Pythagorean Triple numbers less than 1000.
Fortunately I was able to find the algorithm for it, Here it is:
for (int a = 1; a < 1000; a++)
{
for (int b = a; b < 1000; b++)
{
for (int c = b; c < 1000; c++)
{
if ((a * a) + (b * b) == (c * c))
{
cout << "( " << a << ", " << b << ", " << c << " )";
cout << endl;
}
}
}
}
But I don't understand a thing about this code!
Why does the initial value of each loop start from the value of the previous loop ? While the initial value of each loops can be started from 1 !
What's the reason for this ?

For a < b :
Pythagorean triples appear in pairs i.e. (a,b,c) and (b,a,c) : a,b < c ∀ a,b,c ∈ ℕ. Since other one of the pair becomes a trivial solution if one is found. Suppose a Pythagorean triple (a,b,c) is found such that a < b then we immediately know that (b,a,c) is also a Pythagorean triple so we don't want our program to search for it as it will just increase the search domain and thus the execution time. To avoid that, loops are set as a≤b. However, you can also initiate them as a < b or b = a + 1
For b < c or a < b < c:
You can initiate them as a < b < c or (c = b + 1 and b = a + 1) because no Pythagorean triple can be of form (b,b,c) as b^2 + b^2 = 2 * b^2 = c^2, that means c = b * sqrt(2) in which c is an integer and b * sqrt(2) is an irrational number, so the two can never be equal and integer solution can never exist. But c = b * sqrt(2) also says that c > b.
Therefore, a < b < c

Pythagorean triplets have only one way of being ordered: if a² + b² = c² then one can prove than a² + c² ≠ b² and b² + c² ≠ a².
From the above and a few special cases (a = 0 is excluded by definition, a ∊ (0, 2] are easy to check by hand), it follows that one only has to check triplets for which 2 < a ≤ b < c, and this is (almost) what the tree loops do.
There are two reasons for this:
By setting up the loop so that a ≤ b ≤ c we guarantee that no triplet appears more than once
There are fewer triplets to test, so we reduce the execution time by a constant factor.

Related

Count sum of a subset of an array without bruteforcing it

I'll start by explaining step by step what I have to do. First I make an array containing N prime numbers that I create like this:
bool isPrime(int n) {
if(n <= 1) return false;
for(int i = 2; i * i <= n; i++)
if(n % i == 0) return false;
return true;
}
int p[n + d], j = 0;
for(int i = 0; j < n + d; i++) {
if(isPrime(i)) {
p[j] = i;
j++;
}
}
I then create a target array Q that I'm going to be using for the calculations:
int q[n];
for(int i = 0; i < n; i++) {
q[i] = p[i] * p[i + d];
}
Now that I have the traget array Q[N] I need to count how many times this equation is true A + B + C + D = E, where {A, B, C, D, E} are items from the array Q and A <= B <= C <= D. I tried this solution, but it's bruteforcing it and for bigger numbers it just takes minutes to calculate, which is not what I want.
int amount = 0;
for(int i = 1; i < n; i++) {
for(int j = i - 1; j >= 0; j--) {
for(int k = j; k >= 0; k--) {
for(int l = k; l >= 0; l--) {
for(int m = l; m >= 0; m--) {
if(q[j] + q[k] + q[l] + q[m] == q[i])
amount++;
}
}
}
}
}
cout << amount << endl;
For example if I input 15 for N and 1 for D the output should be 2 because:
6 + 15 + 323 + 323 = 667
6 + 143 + 221 + 1147 = 1517
But the code has to be optimized enough to calculate fast for N and D up to 2500.
To optimize this you have to invest your mathematical knowledge.
You should start from calculating prime using Sieve of Eratosthenes or some better algorithm.
Then note that all your q but first must be odd. All primes except 2 are odd and all their multiplication is odd too. As a result only first item in q is even.
Why this is important? Your sum has even number of elements, so to be able to have odd outcome which could match E in q, A must be equal to first element of q since it only even value in q.
So you have only 3 free parameters: B, C and D and E can be calculated and check if it exists.
You can iterate over B, C, D and then binary search for E in q. This will gives algorithm with complexity O(n^3 log n) which is great comparing to your O(n^5).
You can use unordered_set to match E in O(1) time instead of O(log n) time. So final algorithm easily ca be O(n^3).
I'm quite sure you can find this kind tricks more effectively. Possibly knowledge of d value could be used in some way to avoid some iterations.
I have one trick to improve #MarekR's answer from time O(n^3) to O(n^2 log(n)). (Unfortunately it also needs O(n^2) memory.)
As noted, A has to be the first element. So we just have to find the other four elements.
Now here is the trick. Generate one array of tuples (B+C, B, C) with B < C. And another array of tuples (E-D, E, D) with D < E. Sort both arrays. Now walk them in parallel, looking to match up cases where A + B+C = E-D. Filter out the cases where D <= C and voila!
Generating the arrays is O(n^2). Sorting them is O(n^2 * log(n)). Walking them in parallel and grouping by value is O(n^2). Processing a group of matches with m1 entries in the first array and m2 in the second is O(m1 * m2). You are generating extra matches per answer, but given how few answers there are, I believe that this is negligible. Which makes it O(n^2 log(n)).
Code can do better than O(n^3)
Use math knowledge.
For A+B+C+D=E as prime to be true, consider the case where A+B+C+D are all odd. In that case, the sum E of 4 odd numbers is an even. Since the only even prime is 2 and sum of 4 odd primes is more than 2, A,B,C,D can not be all odds. Thus A==2.
Form an array BC containing all combinations of [0...N)[B..N) and 3 items: B, C, Sum B+C. Sort by the Sum. O(N * N * log(N)). I suspect the sorted list can be formed perhaps even closer to O(N * N), given the initial list of primes is itself ordered. Hmmm.
Form an array DE in similar fashion with the difference of E-D.
Walk array BC and then walk DE in the reverse direction looking for A+B+C+D=E.
Estimate O(N * N)* log(N)) after prime table made.
For prime, use Sieve of Eratosthenes

How to Calculate A to the power B without use of multiplication and divsion operator?

I need to find A raise to the power b, simply power ( a, b ) without the use of multiplication and division operator
Ex: pow ( 2, 3 ) = 8
I am unable to understand the intuition behind this code.
int pow(int a, int b)
{
if (b == 0)
return 1;
int answer = a;
int increment = a;
int i, j;
for(i = 1; i < b; i++)
{
for(j = 1; j < a; j++)
{
answer += increment;
}
increment = answer;
}
return answer;
}
well the inner loop multiplies a by itself by adding it to itself a times.
the outer loop does this b times
It works like this:
If the exponent is zero you just return 1. Otherwise you need to do a calculation.
The inner loop, i.e.
for(j = 1; j < a; j++)
{
answer += increment;
}
performs a multiplication. The result of executing that code is equivalent to
answer += increment * a;
And the outer loop is repeating that multiplication b - 1 times (because answer starts as a, so you need one less multiplication as if you were starting with answer = 1), I.e. in total you get
answer += ((a * a) * a ) ... *a
for b-1 times in total, which is equivalent to a^b.
...power ( a, b ) without the use of multiplication and division
operator
To avoid multiplication, note that 3 x 5 means either
3+3+3+3+3
or
5+5+5.
For power, note that 3 ^ 3 (i.e. 3 cubed) means 3 x 3 x 3. The multiplications in this product can be replaced with additions (i.e. 3 x 3 => 3+3+3, and then 9 x 3 = 9+9+9 = 27).

Need to generate x (input) number of letters, then put them into char arrays of 4

The input can be only 5, 7 or 9. Lets say in this case the input is 5, so the program generates 5 * 4 letters: "D E C B E D E D B D E D A C B E A A C B", now i need to put them into arrays of 4, so 5 char arrays, but I don't know how to do that. Here's how i generate the letters. I put all generated ones in one char array, but I also don't know how to separate it into smaller char arrays of 4. Another problem is, as I mentioned, the input changes in every run, but can be either 5, 7 or 9, so the program doesn't know how many arrays of 4 will it need.
I can't use vectors and can only use standard library because of the terms.
for (int i = 0; i < (input * 4); ++i) {
int n = (rand() % 5) + 1;
char kar = (char) (n + 64);
letters[i] = kar;
}
Here is how i print it, if I put all generated letters in one array:
for (int j = 0; j < input* 4; ++j) {
if (j % 4 == 0) {
cout << "\nLetters in the " << (j / 4) + 1 << ". array: ";
}
cout << letters[j] << " ";
}
I need the output like this as it is now, but with separated arrays.
Letters in the 1. array: D E C B
Letters in the 2. array: E D E D
Letters in the 3. array: B D E D
Letters in the 4. array: A C B E
Letters in the 5. array: A A C B
All you need are nested arrays, like this letters[][].
However, you can't have variable sized arrays in c++. But you have an upper bound of 9, so you can do
char letter[9][4];
for (int i = 0; i < input; ++i)
for (int j = 0; j < 4; ++j)
letter[i][j] = ...
I would recommend using std::vector though. You requirement of "I can't use vectors and can only use standard library because of the terms." seems contradictory.
Also, avoid the c-style cast here (char) (n + 64). Prefer to do static_cast<char>(n + 64).
Also, rand() is not a recommended way to generate random numbers. See this for an example of how to generate random numbers well.

Checking whether "1" or "0" is at "x" position in powers of 10 sequence (1101001000...) C++

So I've got this problem to solve. Having a sequence of powers of 10 written one after another, the beginning would look like this: 1101001000... Check whether given number corresponds to "1" or "0" in this sequence.
First input: N number defining how many tests are there. Second input: N lines with a number to check. Output: N numbers that are either "1" or "0".
Example:
Input:
4
3
14
7
6
Output:
0 0 1 0
So I've got this:
#include <iostream>
using namespace std;
int main() {
int a, b;
cin >> a;
for (int k = 1; k <= a; k++){
cin >> b;
int flag = 0;
for (int s = 1; s <= b; s++){
if (((s * (s - 1)) / 2) + 1 == b){
flag = 1;
break;
}
}
if (flag == 1)
cout << "1" << endl;
else
cout << "0" << endl;
}
return 0;
}
and it should work, but the debugger/tester at my school says that time limit has been exceeded, either program takes too long or the program never ends and I'm clueless where's the error. Started programming a month ago so no fancy stuff please.
((s*(s-1))/2)+1 gives "1" places in the sequence.
You're solution is clever. Your idea is to jump over all 1's in the binary string by using a closed formula to get the position of the s-th 1 in the sequence. If the sequence has a 1 at b, you find that very quickly by iterating over s, since for some s, the conditition ((s * (s - 1)) / 2) + 1 == b becomes true. So far it is ok.
However, if the sequence has a 0 at b, that condition is never true. You never hit a 1, and you only check that in your condition. So if for one value of s, the formula is < b, and for the next it is > b, you jumped over b. But you continue the for-loop of s until s > b and that is way to much time to spend.
So in a nutshell, you need to check for > b. If this is the case, you know that the sequence has a 0 at b. Simply break; out of the loop in this case.
You can even improve that by inverting your formula to compute s directly from b. For this, solve the formula for s. That gives you s = 0.5*(sqrt(8*b-7)-1) (Note that the negative solution is irrelevant). This is a computation over the real numbers, so you are going to need floating point numbers for that, and the result is a floating point number, too.
If s turns out to be an integral number, you hit a 1, and 0 otherwise. But checking the result to be integral is error-prone (floating point arithmetic introduces some predictable but unavoidable rounding errors). So instead I'd recommend to use the forward formula (the one you already have) with the rounded-down and rounded-up results of this inverted formula. In other words, guess s using a floating point inverse formula, use this s to check two possible candidates for an integral s against your forward formula.
float guess_s = 0.5*(sqrt(8*b-7)-1);
int s1 = floor(guess_s); // rounded down
int s2 = s1 + 1; // rounded up
Then check s1 and s2 with your formula:
if ( ((s1 * (s1 - 1)) / 2) + 1 == b || ((s2 * (s2 - 1)) / 2) + 1 == b )
cout << "1" << endl;
else
cout << "0" << endl;

Finding MAX of numbers without conditional IF statements c++ [duplicate]

This question already has answers here:
Mathematically Find Max Value without Conditional Comparison
(18 answers)
Closed 9 years ago.
So i have too get two numbers from user input, and find the max of the two numbers without using if statements.
The class is a beginner class, and we have too use what we already know. I kinda worked something out, but it only works if the numbers are inputted with the max number first.
#include <iostream>
using namespace std;
int main()
{
int x = 0, y = 0, max = 0;
int smallest, largest;
cout << "Please enter 2 integer numbers, and i will show you which one is larger: ";
cin >> x >> y;
smallest = (x < y == 1) + (x - 1);
smallest = (y < x == 1) + (y - 1);
largest = (x < y == 1) + (y - 1);
largest = (y > x == 1) + (x + 1 - 1);
cout << "Smallest: " << smallest << endl;
cout << "Largest: " << largest << endl;
return 0;
}
Thats what i have so far, but after putting different test data in, i found out it only works for numbers such as 4,5 or 6,7. But numbers with more then 2 spaces between eachother they dont such as, 4,8 or 5, 7. Any help would be appreciated.
I saw this question in Cracking the Coding interview book.
Let’s try to solve this by “re-wording” the problem We will re-word the problem until we get something that has removed all if statements
Rewording 1: If a > b, return a; else, return b
Rewording 2: If (a - b) is negative, return b; else, return a
Rewording 3: If (a - b) is negative, let k = 1; else, let k = 0 Return a - k * (a - b)
Rewording 4: Let c = a - b Let k = the most significant bit of c Return a - k * c
int getMax(int a, int b) {
int c = a - b;
int k = (c >> ((sizeof(int) * CHAR_BIT) - 1)) & 0x1;
int max = a - k * c;
return max;
}
Source: http://www.amazon.com/Cracking-Coding-Interview-Programming-Questions/dp/098478280X
Edit: This code works even when a-b overflows.
Let k equal the sign of a-b such that if a-b >=0, then k is 1, else k=0.Let q be the inverse of k. Above code overflows when a is positive or b is negative, or the other way around. If a and b have different signs, then we want the k to equal sign(a).
/* Flips 1 to 0 and vice-versa */
public static int flip(int bit){
return 1^bit;
}
/* returns 1 if a is positive, and 0 if a is negative */
public static int sign(int a){
return flip((a >> ((sizeof(int) * CHAR_BIT) - 1)) & 0x1);
}
public static int getMax(int a, int b){
int c = a - b;
int sa = sign(a-b); // if a>=0, then 1 else 0
int sb = sign(a-b); // if b>=1, then 1 else 0
int sc = sign(c); // depends on whether or not a-b overflows
/* If a and b have different signs, then k = sign(a) */
int use_sign_of_a = sa ^ sb;
/* If a and b have the same sign, then k = sign(a - b) */
int use_sign_of_c = flip(sa ^ sb);
int k = use_sign_of_a * sa + use_sign_of_c * sc;
int q = flip(k); //opposite of k
return a * k + b * q;
}
Here is a funny solution:
int max_num = (x>y)*x + (y>=x)*y;
Assuming that you have covered bitwise operators already you can do this:
max = a-((a-b)&((a-b)>>(sizeof(int)*8-1)));
This is based off of the solution from Mathematically Find Max Value without Conditional Comparison that #user93353 pointed out in the comments above.
This may be overkill if you really are just trying to avoid if statements, not comparisons in general.
You can try this code to find max and min for two input variables.
((a > b) && (max = a)) || (max=b);
((a < b) && (min = a)) || (min=b);
For three input variables you can use similar method like this:
int main()
{
int a = 10, b = 9 , c = 8;
cin >> a >> b >> c;
int max = a, min = a;
// For Max
((a > b) && (a > c) && (max=a)) ||
((b > c) && (b > a) && (max=b)) ||
(max=c) ;
// For min
((a < b) && (a < c) && (min=a)) ||
((b < c) && (b < a) && (min=b)) ||
(min=c) ;
cout << "max = " << max;
cout << "and min = " << min;
return 1;
}
One run is:
:~$ ./a.out
1
2
3
max = 3 and min = 1
Edit
Thanks to #Tony D: This code will fail for negative numbers.
One may try this for negative numbers for two inputs to find max(not sure for this):
((a > b) && ( a > 0 && (max = a))) || ((b > a) && (max = b)) || (max = a);