Cannot understand comma expression - c++

#include <iostream>
using namespace std;
int main()
{
int a, b, c, max;
cout<<"a="; cin>>a;
cout<<"b="; cin>>b;
cout<<"c="; cin>>c;
a>b?(max=a, a=b, b=max):a;
b>c?(max=b, b=c, c=max):a;
a>b?(max=a, a=b, b=max):a;
cout<<a<<" "<<b<<" "<<c;
}
This is a code where you can input 3 random numbers and it will put them in order. I don't understand this part, however:
a>b?(max=a, a=b, b=max):a;
b>c?(max=b, b=c, c=max):a;
a>b?(max=a, a=b, b=max):a;
How does it work, and why?
Let's say a = 6, b = 54, and c = 12.
a>b?(max=a, a=b, b=max):a; <-- sets max to 6, then a to 54, then 54=max. then compares 6 to 54 which is false and writes a (6) as the first number?
b>c?(max=b, b=c, c=max):a; <-- sets max to 54, b=12, 12=max. then compares 54 to 12 which is true in our case and writes c=12 as the second number?
a>b?(max=a, a=b, b=max):a; <-- sets max to 6, a=54, 54=max. then compares 6 to 54 which is false and writes 6 again, wtf?
The program itself works correctly. I just don't understand how the algorithm works.

This:
cond ? A : B
is roughly equivalent to this:
if (cond) {
A;
} else {
B;
}
This:
(X, Y, Z)
is roughly equivalent to this:
X;
Y;
Z;
i.e. each expression is evaluated completely, in turn.
Using these two rules, you should be able to trace the execution of your code. However, that code is grotesque, and should never have been written like that. So my recommendation is to just ignore it, and write the algorithm properly.

All the code's doing is abusing the comma operator's ability to do multiple things in one to swap values in one statement.
The first line finds the max of the first two numbers. The second finds the max of that and the third, so that it's now found the largest of the three. The third line sorts the other two in order afterwards.
It's about the same as this:
if (a > b)
swap (a, b); //b is max(a,b)
if (b > c)
swap (b, c); //c is max(max(a,b),c), which is largest
if (a > b)
swap (a, b); //b is max (a, b), so numbers are in order smallest to largest

a>b?(max=a, a=b, b=max):a
The final ":a" really doesn't do anything, it could just as easily have been ":0". It is essentially the statement that is to be carried out if the "a>b" is false. but since the a isn't assigned to anything, it doesn't do anything. so in this case
if(a > b){
max = a;
a = b;
b = max;
}
It uses the max variable to swap a and b; The SAME algorithm is used for the following two lines. So essentially
if a > b then swap them
now if b (which could hold a) > c then swap them
now if a (which could hold the older b) > b(which could hold the oldest c) then swap

Well, essentially I this is what happens.
a>b?(max=a, a=b, b=max):a;
the first section is just a normal comparison in the fashion of a tertiary if statement, so basically it checks if a>b, then ? is just equal to the first brackets set, so if its true, it evaluates the first section otherwise then the code after : is just like else and that is is evaluated.. The (max=a, a=b, b=max) basically evaluates each item in turn, so first max is set to a, then a = b and finally b = max; Same for the other two lines.
You can read more here: http://www.cplusplus.com/doc/tutorial/operators/
Hope this helped.

Related

What does the expression "b=(b-x)&x" mean?

Given that x is a set, the following code goes through the subsets of a set x:
int b = 0;
do {
// process subset b
} while (b=(b-x)&x);
I came across this reading about bit manipulation and how it's used to represent sets.
What does the expression b=(b-x)&x mean? How does it work?
I'm familiar with == but not with = being here in the do while loop. How does that work? Does the loop terminate when the value of (b-x)&x becomes zero?
The usage of the code is as follows:
#include <iostream>
using namespace std;
void subsets(int x, int b){
do{
cout << b<<"\n";
}while(b = (b-x)&x);
}
int main()
{
int x = (1<<1)|(1<<3)|(1<<4)|(1<<8);
int b = 0;
subsets(x, b);
return 0;
}
The output given by the above code is:
0
2
8
10
16
18
24
26
256
258
264
266
272
274
280
282
Easy parts first:
Does the loop terminate when the value of (b-x)&x becomes zero? I'm familiar with == but not with = being here in the do while loop. How does that work?
Yes.
A do/while loop like this:
do{
cout << b<<"\n";
}while(b = (b-x)&x);
does the following steps:
Execute cout << b<<"\n";.
Execute b = (b-x)&x and remember the result.
If the result isn't zero, go back to step 1.
= is assignment. It sets a variable to a value, as in i = 0;. But... huh? What's the result of an assignment? In C, the result of an assignment is the value that was assigned. This lets you write a = b = c = 0;, to set three variables a, b and c to 0. This is equivalent to a = (b = (c = 0));, i.e. it sets c to 0, then it sets b to the result of that, then it sets a to the result of that. (In C++ it's possible to write a class which doesn't follow this rule, but we're only dealing with ints here, not classes)
Some people like to use this trick to make their code shorter. You could've written it like this instead:
do{
cout << b<<"\n";
b = (b-x)&x;
}while(b);
What does the expression b=(b-x)&x mean?
= is assignment. - is subtraction. & is "bitwise AND".
This subtracts x from b. Then, it bitwise-ANDs the answer to that with x. Then, it sets b to the answer to that.
What is bitwise AND? Bitwise AND is an operation where you write down the numbers in binary, lines them up, then creates a new number, where each bit is 1 if the bits in both inputs are 1, and 0 otherwise. Example:
01011010 = 90
& 11101000 = 232
-----------------
01001000 = 72
so 90 & 232 is 72.
How does it work?
This program is basically treating the numbers as binary. Each bit in x is 1 to say something is "in the set", or 0 to say that it's not.
b then goes through all the possible combinations of those bits. b = (b-x) & x; is a bit of a "voodoo magic spell" to change the combination to the next one in order, for example:
- 000000000 <- b the first time
011001001 <- x
-----------------
100110111 <- b-x
& 011001001 <- x
-----------------
000000001 <- (b-x)&x (b the second time)
- 011001001 <- x
-----------------
100111000 <- b-x
& 011001001 <- x
-----------------
000001000 <- (b-x)&x (b the third time)
- 011001001 <- x
-----------------
100111111 <- b-x
& 011001001 <- x
-----------------
000001001 <- (b-x)&x (b the fourth time)
...etc...
You can be sure that whoever invented this trick was very clever.

GCD of numbers confusion

I was looking for simple code for calculating gcd of 2 numbers and came across this code which works
ll gcd(ll a, ll b){
return b ? gcd(b,a%b):a;
}
I was trying to make this code work
ll gcd(ll a, ll b){
return a ? gcd(a%b,b):b;
}
No matter what I do, I am not able to get the second code block to work. My reason is simple, no matter how I start, I should be able to get GCD. Can someone please help me understand where I am going wrong?
If you want to swap a and b, you must do two things:
Replacing every a with a b and every b with an a
Changing the order of the arguments passed to each recursive call to gcd.
You have done it partially. What you need to do is:
return a ? gcd(b%a, a):b;
What you have generates infinite recursion. For example, if you call gcd (12, 8) with your modified function, this is what you get at each iteration:
a = 12, b = 8
a = 4, b = 8
a = 4, b = 8
a = 4, b = 8
...

How does that recursive function work?

Might be a very basic question but I just got stuck with it. I am trying to run the following recursive function:
//If a is 0 then return b, if b is 0 then return a,
//otherwise return myRec(a/2, 2*b) + myRec(2*a, b/2)
but it just gets stuck in infinite loop. Can anybody help me to run that code and explain how exactly that function works? I built various recursive functions with no problems but this one just drilled a hole in my head.
Thanks.
Here is what I tried to do:
#include<iostream>
int myRec(int a, int b){
if (a==0){
return b;
}
if (b==0){
return a;
}
else return myRec(a/2, 2*b) + myRec(2*a, b/2);
}
int main()
{
if (46 == myRec(100, 100)) {
std::cout << "It works!";
}
}
Well, let us mentally trace it a bit:
Starting with a, b (a >= 2 and b >= 2)
myRec(a/2, 2*b) + something
something + myRec(2*a', b'/2)
Substituting for a/2 for a' and 2*b for b', we get myRec(2*(a/2), (b*2)/2), which is exactly where we started.
Therefore we will never get anywhere.
(Note that I have left out some rounding here, but you should easily see that with this kind of rounding you will only round down a to the nearest even number, at which point it will be forever alternating between that number and half that number)
I think you are missing on some case logic. I last program in C ages ago so correct my syntax if wrong. Assuming numbers less than 1 will be converted to zero automatically...
#include<iostream>
int myRec(int a, int b){
// Recurse only if both a and b are not zero
if (a!=0 && b!=0) {
return myRec(a/2, 2*b) + myRec(2*a, b/2);
}
// Otherwise check for any zero for a or b.
else {
if (a==0){
return b;
}
if (b==0){
return a;
}
}
}
UPDATE:
I have almost forgot how C works on return...
int myRec(int a, int b){
if (a==0){
return b;
}
if (b==0){
return a;
}
return myRec(a/2, 2*b) + myRec(2*a, b/2);
}
VBA equivalent with some changes for displaying variable states
Private Function myRec(a As Integer, b As Integer, s As String) As Integer
Debug.Print s & vbTab & a & vbTab & b
If a = 0 Then
myRec = b
End If
If b = 0 Then
myRec = a
End If
If a <> 0 And b <> 0 Then
myRec = myRec(a / 2, 2 * b, s & "L") + myRec(2 * a, b / 2, s & "R")
End If
End Function
Sub test()
Debug.Print myRec(100, 100, "T")
End Sub
Running the test in Excel gives this (a fraction of it as it overstacks Excel):
T: Top | L: Left branch in myRec | R: Right branch in myRec
The root cause will be the sum of the return which triggers more recursive calls.
Repeating of the original values of a and b on each branch from level 2 of the recursive tree...
So MyRec(2,2) = MyRec(1,4) + MyRec(4,1)
And MyRec(1,4) = MyRec(.5,8) + MyRec(2,2)
So MyRec(2,2) = MyRec(.5,8) + MyRec(2,2) + MyRec(4,1)
Oops.
(The .5's will actually be zeroes. But it doesn't matter. The point is that the function won't terminate for a large range of possible inputs.)
Expanding on gha.st's answer, consider the function's return value as a sum of expressions without having to worry about any code.
Firstly, we start with myRec(a,b). Let's just express that as (a,b) to make this easier to read.
As I go down each line, each expression is equivalent, disregarding the cases where a=0 or b=0.
(a,b) =
(a/2, 2b) + (2a, b/2) =
(a/4, 4b) + (a, b) + (a, b) + (4a, b/4)
Now, we see that at a non-terminating point in the expression, calculating (a,b) requires first calculating (a,b).
Recursion on a problem like this works because the arguments typically tend toward a 'base case' at which the recursion stops. A great example is sorting a list; you can recursively sort halves of the list until a list given as input has <= 2 elements, which is trivial without recursion. This is called mergesort.
However, your myRec function does not have a base case, since for non-zero a or b, the same arguments must be passed into the function at some point. That's like trying to sort a list, in which half of the list has as many elements as the entire list.
Try replacing the recursion call with:
return myRec(a/2, b/3) + myRec(a/3, b/2);

Advice for POUR1 on SPOJ?

I need help with this problem POUR1. I think
it can be solved with bruteforce approach, but I read that it is a graph problem (BFS). I solved problems like ABCPATH, LABYR1, PT07Y, PT07Z, BITMAP, ...
But I don't know how to approach POUR1 in BFS manner.
Can someone give me some advice?
Problem statement:
Given two vessels, one of which can accommodate a litres of water and the other - b litres of water, determine the number of steps required to obtain exactly c litres of water in one of the vessels.
At the beginning both vessels are empty. The following operations are counted as 'steps':
emptying a vessel,
filling a vessel,
pouring water from one vessel to the other, without spilling, until one of the vessels is either full or empty.
Input:
An integer t, 1<=t<=100, denoting the number of testcases, followed by t sets of input data, each consisting of three positive integers a, b, c, not larger than 40000, given in separate lines.
Output:
For each set of input data, output the minimum number of steps required to obtain c litres, or -1 if this is impossible.
Example:
Sample input:
2
5
2
3
2
3
4
Sample output:
2
-1
This question has a simpler solution. No need for BFS. Ad-hoc would do good.
method 1 - fill A, empty it into B. whenever A becomes empty fill it back, whenever B becomes full empty it. (all the above-mentioned actions count as individual moves). Continue this process until you arrive at the required amount of water in any one of the vessels. Get the number of moves here. (say C1).
method 2 - fill B, empty it into A. whenever B becomes empty fill it back, whenever A becomes full empty it. Continue this until you arrive at the required amount. Get the number of moves say C2).
The answer is min(C1,C2).
Source code in C++:
#include < cstdio >
#include < algorithm >
using namespace std;
int pour(int A, int B, int C) {
int move = 1, a = A, b = 0, tfr;
while (a != C && b != C) {
tfr = min(a, B - b);
b += tfr;
a -= tfr;
move++;
if (a == C || b == C)
break;
if (a == 0) {
a = A;
move++;
}
if (b == B) {
b = 0;
move++;
}
}
return move;
}
/** Reason for calculating GCD of a,b is to check whether an integral solution of
* equation of form ax + by = c exist or not, to dig deeper read Diophantine Equations
*/
int gcd(int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
int main() {
int t, a, b, c;
scanf("%d", & t);
while (t--) {
scanf("%d%d%d", & a, & b, & c);
if (c > a && c > b)
printf("-1\n");
else if (c % gcd(a, b) != 0)
printf("-1\n");
else if (c == a || c == b)
printf("1\n");
else
printf("%d\n", min(pour(a, b, c), pour(b, a, c)));
}
return 0;
}
Consider the set of all a priori possibles states (eg [3, 7] meaning Vessel1 contains 3 litters and vessel2 contains 7 litters). You have a directed graph whose vertices are those states and whose edges are the possible moves. The question is to find a path in the graph joining the state [0, 0] to either a state of type [c, ?] or a state of type [?, c]. Such a path is typically searched by a BFS.

C++ Operator (unsure of)

Is there a c++ operator that i could use for a for loop where it would add or subtract to variables based on whether one of the variables is less than or greater 0.
For instance
int a;
int b;
for(int i=0;i<some_number; i++)
result = a +< b
result = a-> b
No.
You can combine with the ?: operator.
int a;
int b;
for(int i=0;i<some_number; i++)
result = (a < b)? result+b:result-b;
That is if I understood your example correctly.
-> is an existing dereference operator.
Operator ?: is an equivalent to the if...else construct. If the statement before ? evaluates to true, the statement right after the ? gets executed, otherwise the statement after the : gets executed.
Do you want something like this?
result += a > 0 ? b : -b;
Note that this will subtract b if a == 0, which isn't quite what you asked for.
Not directly, but the ternary operator is close.
for(int i=0;i<some_number; i++)
result = (a > 0)?(a):(b);
This line will be equivalent to result = a when a is greater than 0, and result = b elsewise.
It could also be written as result = a?a:b;, but the longer form is more readable.
Not sure if this would be any help?
result = a + (b*(a < b));
result = a - (b*(a > b));
Basically, (a < b) is converted into a boolean, which is basically either 1 (true) or 0 (false). b multiplied by 0 is of course zero, so nothing is added, and b multiplied by 1 is exactly b's value.