The CSES problem Josephus Problem I requires us to print the sequence of how people are chosen for n people and k = 2. I found an elegant solution to this here.
Basically, the code is similar to this:
void J(int n)
{
int a = 1, b = 0;
while (n > 0)
{
for (int i = 2; i <= n; i += 2)
{
cout << a * i + b << ' ';
}
if (n & 1)
cout << a + b << ' ', b += a;
else
b -= a;
a <<= 1;
n >>= 1;
}
}
Can someone explain why it works?
I made a few changes to the code to illustrate how it works.
void J(int n)
{
int a = 1, b = 0;
while (n > 0)
{
std::cout << "n=" << n << std::endl;
std::cout << "a=" << a << ", b=" << b << std::endl;
for (int i = 2; i <= n; i += 2)
{
std::cout << a * i + b << ' ';
}
if (n & 1) // equivalent to n % 2 == 1 (if n is odd)
std::cout << '*' << a + b << ' ', b += a;
else
b -= a;
std::cout << std::endl;
a <<= 1; // a = a * 2;
n >>= 1; // n = n / 2;
}
}
The first thing to note is that the variables a and b are initialized to values that allow us to compute the positions of people who will be eliminated as we go around the circle (also using the iterator i in the for loop). The initial values of a = 1, b = 0 are so we can eliminate every even numbered person on the first iteration.
Next, every time through the while(n) loop, half of the remaining people will be eliminated. If n is odd, we loop back to the beginning of the circle and also eliminate the person at the start of the current iteration.
I think the tricky part here is how the values of a and b change in the if statement. If n is odd we increment b by the value of a. If n is even we subtract the value of a from b. Then we double the value of a to get ready for the next iteration around the circle. The values of a and b are chosen to account for the gaps in the circle left by eliminating positions in the previous iterations.
Finally, we divide n by 2 before the next iteration, since there are half as many people left in the circle. Here's a sample run for n=19.
Output:
n=19
a=1, b=0
2 4 6 8 10 12 14 16 18 *1
n=9
a=2, b=1
5 9 13 17 *3
n=4
a=4, b=3
11 19
n=2
a=8, b=-1
15
n=1
a=16, b=-9
*7
Related
using namespace std;
int main()
{
cout << "\n\n Find the perfect numbers between 1 and 500:\n";
cout << "------------------------------------------------\n";
int i = 1, u = 1, sum = 0;
cout << "\n The perfect numbers between 1 to 500 are: \n";
while (i <= 500)
{
while (u <= 500)
{
if (u < i)
{
if (i % u == 0)
sum = sum + u;
}
u++;
}
if (sum == i) {
cout << i << " " << "\n";
}
i++;
u = 1;
sum = 0;
}
}
why we added u=1 and sum=o in the last two lines? Can somebody help me with this? I am not able to comprehend the logic behind changing the logic at the end.
Those lines are for re-initializing the variables.
The code you have posted is for finding the perfect numbers which are just numbers that equals the sum of its own proper divisors. eg: 6, the proper divisors are 1, 2, 3. sum of 1 + 2 + 3 = 6. So, 6 is a perfect number.
The first while loop
while (i <= 500)
is for going through the numbers between 1 and 500 one by one
and the second while loop
while (u <= 500)
is for checking the divisors for a particular i. At first the loop will run for i = 1, the second while loop runs for 500 times and check the divisors of 1. Now, for i = 2, we have to check the divisors again from u = 1 right, so the re-initialization is done after the second while loop.
actually you should change the second loop to
while (u < i)
or even better
while (u <= (i / 2))
I am implementing a simple greedy merging algorithm that merges the two points which are closest to each other and averages their position. After merging two points at indices i and j, I need to replace one of them, say i, by the mean of the two points. Then, copy the last point in the array over the other point, say j, after which I can reduce the array size by 1 with all remaining points being within the new reduced range.
I need to repeat the above step until there are only 3 representative points left, each of which represents a group of merged points. I have written the following code, but I guess it is not able to update the array (pts). I would appreciate if anyone could help me figure out the mistake. Thanks in advance. This is my code:-
void merge_point(Point pts[], int &size) {
double a;
int x, y;
Point d;
while(size != 3) {
double min = get_distance(pts[0],pts[1]);
for (int i = 0; i < size; i++) {
for (int j = i+1; j < size; j++) {
get_distance(pts[i], pts[j]);
if ((a = get_distance(pts[i],pts[j])) <= min) {
x = i;
y = j;
}
a = get_distance(pts[i],pts[j]);
}
}
d = mean_point(pts[x],pts[y]);
pts[x] = d;
pts[y] = pts[size-1];
size = size - 1;
}
}
When I am entering the input array as :-
3 8 2
5.7 7.2 2.2
10.83 6.48 2.42
20.577 5.832 2.662
39.0963 5.2488 2.9282
74.283 4.72392 3.22102
141.138 4.25153 3.54312
268.162 3.82638 3.89743
509.507 3.44374 4.28718
968.063 3.09936 4.7159
My expected output should be:-
181.974 4.29686 3.57395
968.063 3.09936 4.7159
509.507 3.44374 4.28718
But, I am getting an output of:-
4.35 7.6 2.1
968.063 3.09936 4.7159
36.6506 5.8958 2.68145
Think I find out the problem, you don't update the min distance as soon as you find a new one during the cicle, try this:
cout << "distance between p[" << i << "] and " << "p[" << j << "]" << "is " << get_distance(pts[i], pts[j]) << '\n';
if ((a = get_distance(pts[i], pts[j])) <= min)
{
cout << "current min distance is between point[" << i << "]" << " and point[" << j << "]" << '\n';
min = a;
x = i;
y = j;
}
you've got to add this instruction:
min = a;
in order to update the min.
Otherwise it will works only for some edge cases.
The following code takes in an integer t and then takes in 3 more integers t times and returns the maximum number of times you can subtract 1 from two different integers at the same time, whereas the program stops when there is only 1 integer above 0 remaining. I have solved the problem, but I want to reduce the time complexity of the code and I don't know how.
#include <bits/stdc++.h>
using namespace std;
int main() {
long long t, r, g, b, arr[1000], count = 0;
bool isMax=true;
cin >> t;
for (long long i = 0; i < t; i++) {
cin >> r >> g >> b;
arr[0] = r;
arr[1] = g;
arr[2] = b;
for (long long j = 0; j < 3; j++) {
for (long long k = 0; k < 2; k++) {
if (arr[k] > arr[k + 1]) {
long long a = arr[k];
long long b = arr[k + 1];
arr[k] = b;
arr[k + 1] = a;
}
}
}
count = 0;
if (arr[2] == 1) {
cout << 1 << endl;
} else if (arr[0] + arr[1] <= arr[2]) {
cout << arr[0] + arr[1] << endl;
} else {
while (arr[0] > 0) {
while (isMax && arr[0] > 0) {
arr[2]--;
arr[0]--;
count++;
if (arr[2] < arr[1]) {
isMax = false;
}
}
while (!isMax && arr[0] > 0) {
arr[1]--;
arr[0]--;
count++;
if (arr[1] < arr[2]) {
isMax = true;
}
}
}
while (arr[2] > 0 && arr[1] > 0) {
arr[2]--;
arr[1]--;
count++;
}
cout << count << endl;
}
}
}
How can I get the same output without using all these loops that increase the time complexity?
Edit: I don't want my code re-written for me, this is homework and all I want are tips and help so I can reduce the time complexity, which I don't know how to do.
Edit 2: In my algorithm, I sort the 3 numbers in ascending order, then I use a while loop to check if the smallest number (s/arr[0]) is > 0. After that, I use two more while loops to alternate between the largest and medium-size numbers (l/arr[2] and m/arr[1] respectively) and decrement from both variables s and l or m (alternating). When s becomes 0, that will mean I can just decrement l and m till one of them equals 0, and then I print the count variable (I increment count every time I decrement two of the variables).
Im not sure if i understood the problem correctly. But if i did you could optimize the algorithem the following way:
int count = 0;
int a = 20, b = 10, c = 21;
sort(a, b, c); // Function that sorts the numbers, so that a is the smallest and c is the largest
count += a; // count = 10
c -= a; // a = 10, b = 20, c = 11
if(c < b) {
float diff = b - c; // diff = 9
float distribute = diff / 2; // distribute = 4.5
count += b - ceil(distribute); // count = 25
}
else count += b;
You would have to this t times and then sum the count variables, resulting in a complexity of t.
Assuming your code is correct, you can examine exactly what your loops are doing, and look at them more mathematically.
if ( arr[2] == 1 ) {
cout << 1 << endl;
} else if ( arr[0] + arr[1] <= arr[2] ) {
cout << arr[0] + arr[1] << endl;
} else {
while ( arr[0] > 0 ) {
if ( arr[2] > arr[1] ) {
long long min = std::min( std::min( arr[0], arr[2] ), arr[2] - arr[1] + 1 );
arr[0] -= min;
arr[2] -= min;
count += min;
} else {
long long min = std::min( std::min( arr[0], arr[1] ), arr[1] - arr[2] + 1 );
arr[0] -= min;
arr[1] -= min;
count += min;
}
}
count += std::min( arr[2], arr[1] );
cout << count << endl;
}
Assuming your program was correct,t his produces the same results for all inputs I tried.
I'm not sure I understood the problem correctly but if you want to know the maximum number of times you can subtract 1 until hitting zero from two elements in a three element set, I believe the answer should be the same as finding the median element of the set. For example, if I have the set
10 20 30
The maximum amount of times I can subtract 1 is 20, if I always chose to subtract from the subset {20, 30}, while the minimum would be 10, if I always choose to subtract from the subset {10, 20}.
Hope this helps! (Assuming I didn't totally misunderstand the question ^_^ ")
Edit:
After the clarifying comment, I believe all you need to do is find the minimum between the sum of the non-maximum elements and the maximum element. Consider the following examples:
If you are given the set {80, 10, 210} for example, the answer to your problem is 90, because we can subtract 10 from the subset {80, 10}, leaving us with {70, 0, 210} where we can further subtract 70 from the subset {70, 210}, leaving us with {0,0,140}, where we can perform no more operations. We have performed 80+10 = 90 subtractions by 1 In this case, max = 210 and min+med = 90
On the other hand, the consider the set {2,2,2}. We can subtract 2 from the subset {2,2}, leaving us with {0,0,2}, where we can perform no more operations. In this case, we have performed 2 subtractions by 1 Max = 2 and min+med = 4
Last example: consider the set {2,3,5}. We can subtract 2 from the subset {2,3}, leaving us with {0,1,5}, where we can the subtract 1 from the subset {1,5}, resulting in {0,0,4}, where we can perform no more operations. In this case, we have performed 2+3=5 subtractions by 1 Max = 5 and min+med = 5
If you continue performing examples in this vein, you should be able to convince yourself that the solution is always going to be min(max, min+median).
I'm having three integers called a,b,c and need to find the lowest number of them, which isn't 0.
But at the same time it should be able to handle the special case where all the three numbers are 0.
This have to be implemented in C or C++14
Example 1:
a = 4;
b = 0;
c = 1;
Result = c
Example 2
a = 0;
b = 0;
c = 0;
Result = Special case
Example 3
a = 11;
b = 46;
c = 15;
Result = a
So far i haven't been able to find an elegant way to implement this in c or c++.
I've considered to put it in a sorted array, and keep popping the numbers until it get something else than zero. But this seems to be an over-complicated way to do it.
Edit
Forgot to mention that the values i try to find is never negative, but always positive.
Removed the code, since it's should not be a code review
If there is only three values, using simple if statements could be a solution.
Then the logic could be (pseudo-code)
if (a is larger than zero) and (b is larger than zero and a is smaller than b) and (c is larger than zero and a is smaller than c)
a is the smallest
else if (b is larger than zero) and (c is larger than zero and b is smaller than c)
b is the smallest
else if c is larger than zero
c is the smallest
else
all are either zero or negative
Note that each if check gets progressively smaller. That's because the previous condition removes an alternative that doesn't need to be checked further.
This of course works for larger chains of variables, as long as the amount of variables is fixed. It will become unwieldy quite fast though, so for more than three-four variables other methods should be used.
The bulk of the control flow could look like this:
#include <iostream>
int find_smallest_nonzero(int a, int b, int c)
{
if (a > 0 || b > 0 || c > 0) {
if ((b >= a || b == 0) && (c >= a || c == 0) && (a > 0))
return a;
else if ((c >= b || c == 0) && (b != 0))
return b;
else
return c;
} else return -1;
}
int main() {
std::cout
// permutations
<< find_smallest_nonzero(1, 2, 3) << ' '
<< find_smallest_nonzero(2, 1, 3) << ' '
<< find_smallest_nonzero(2, 3, 1) << ' '
// one zeros
<< find_smallest_nonzero(1, 0, 3) << ' '
<< find_smallest_nonzero(0, 1, 3) << ' '
<< find_smallest_nonzero(1, 3, 0) << ' '
// two zeros
<< find_smallest_nonzero(1, 0, 0) << ' '
<< find_smallest_nonzero(0, 1, 0) << ' '
<< find_smallest_nonzero(0, 0, 1) << ' '
// duplicates
<< find_smallest_nonzero(2, 2, 1) << ' '
<< find_smallest_nonzero(2, 1, 2) << ' '
<< find_smallest_nonzero(1, 2, 2) << ' '
<< find_smallest_nonzero(1, 1, 2) << ' '
<< find_smallest_nonzero(1, 2, 1) << ' '
<< find_smallest_nonzero(2, 1, 1) << ' '
// all zeros
<< find_smallest_nonzero(0, 0, 0) << '\n';
}
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -1
it will return the minimum non-zero among a, b and c, unless all are 0, in which case returns -1.
There might be faster ways.
int lowest(int a, int b, int c) {
auto v = {a, b, c};
return *std::min_element(std::begin(v), std::end(v), [](int x, int y) {
return (x < y && x != 0) || y == 0;
});
}
This approach can handle any number of elements. In the special case, the function simply returns zero (there is no need to use a different special value).
You can do the following in C++ using std::min
int a = 0,b = 0,c = 0;
int x = std::min( { a,b,c },
[](const auto& n1, const auto& n2) {
if (not n1)
return false;
if (not n2)
return true;
return n1 < n2;
});
std::string out = x?std::to_string(x):std::string{"Special Case"};
if(a==0 && b==0 && c==0){
return "Special case"
}else{
// now put each equals zero and compare the other, last else compare all three
}
You can write a function printf the output.
hey guys I am trying to calculate pi using this formula:
pi = 4 ยท [ 1 โ 1/3 + 1/5 โ 1/7 + 1/9 ... + (โ1)^n/(2n + 1) ]
yet i always get a zero for my output pi value and I am really confused as to where I had gone wrong. Here is my code:
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
int n;
double b = 0;
char c = 'Y';
int s = 1;
while (c == 'Y') {
cout << "Enter the value of the parameter 'n' in the Leibniz formula (or -1 to quit):" << endl;
cin >> n;
if (n != -1) {
c = 'Y';
for (int a = 1; a <= n; a++) {
s = -s;
b += 4 * (s/ (2 * a + 1));
}
cout << "The approximate value of pi using 1 term is:" << b << endl;
}
else {
c = 'N';
}
}
return 0;
}
In both C and C++, mathematical operations on integers result in an integer even if the result would be fractional in conventional mathematics. Change your int to a float or double and I suspect that it will work better.
The result is truncated to the integer value and has an integer type.
So for example: 2 / 4 results in 0 and 5 / 2 would result in 2.
NOTE if you perform an operation between a floating point value and an integer value, the result is a floating point value. So:
2.0 / 4 == 0.5
Your code seems to be complicated and int type is used in places where floating operations are expected.
Consider the following simplified example:
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
int n = 0;
double b = 0;
double s = 1; // Tytpe is changed
while (n != -1) { // there is no need for char c
cout << "Enter the value of the parameter 'n' in the Leibniz formula (or -1 to quit):" << endl;
cin >> n;
b = 0; // init b before starting the loop
s = 1; // the same for s (it can be -1 from the next user input)
// there is no need for if (n != -1) because for has condition
for (int a = 1; a <= n; a++) {
s = -s;
b += 4 * (s / (2.0 * a + 1));
}
cout << "The approximate value of pi using 1 term is:" << b << endl;
}
return 0;
}
IMPORTANT UPDATE:
To make your calculation correct (in terms of Leibniz's formula) I suggest the following changes in the for loop:
for (int a = 0; a <= n; a+=2) { // start from 0 with step 2
b += 4.0 * (s / (a + 1.0));
s = -s; // change the sign for next calculation
}
and further, consider some kind of optimization
b = 0; // do not forget about reseting b to 0 before making sum
s = 1; // set 1 in the sign
for (int a = 0; a <= n; a+=2) { // start from 0 with step 2
b += s / (a + 1.0); // no multiplication on each iteration
s = -s; // because s was initialized with 1
}
b *= 4.0; // multiply once for the whole sum
UPDATE 2
For case if precision is really important for output, final snippet can be like:
#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
int n = 0;
double b = 0;
double s = 1;
int prec = 0;
cout << "What precision should be used for output? (Value from 1 to 10): ";
while (prec< 1 || prec > 10)
{
cin >> prec;
}
while (true) {
cout << "Enter the value of the parameter 'n' in the Leibniz formula (or -1 to quit):" << endl;
cin >> n;
if (n == -1)
{
break; // go out the loop if user enter -1 (want to exit)
}
else if (n <= 0)
{
cout << "'n' have to be 1 or greater" << endl;
continue; // go to the next iteration to ask new 'n'
}
s = 1;
b = 1.0; // we can start from 1 (no need to claculate the first term) and make loop from 2
for (int a = 2; a < n*2; a+=2) { // start from 2 with step 2 (so n should be doubled)
s = -s; // change the sign for this iteration, because now loop started from a = 2
b += s / (a + 1.0);
}
b *= 4.0;
cout << "The approximate value of pi using 1 term is: " << setprecision(prec+1) << b << " (PI = " << M_PI << ")" << endl;
}
return 0;
}
Note:
In this version b initialized with 1.0 because the first item in the Leibniz series is always 1 (we can skip calculation, but we should change the logic for sign changes - make s = -1; or move s = -s; before summation - I choose the 2nd option).
Also I'am not sure what is "parameter 'n' in the Leibniz formula", so pay attention to condition of for loop - now (with a < n*2) it is correct for case if n is number of items in the Leibniz series to be calculated.
Along with doing integer math, you have a few other minor problems.
First, the formula is [1 - ...], not [0 - ...], so you need to initialize b to 1.0, not 0.
Second, it's supposed to be 4 * [...], but you're multiplying by 4 on every iteration of the loop, so you're getting `[0 - b1 * 4 + b2 * 4 -b3 * 4 ....].
You can distribute the multiplication if you want to, but if you do you'll need to distribute it correctly (e.g., the starting value of 1.0 would also need to be multiplied by 4).
Also note that you're not re-initializing correctly, so the second (and subsequent) times you attempt to re-compute the value, you'll get completely incorrect answers (until you fix more stuff).
You've been burned by integer division.
b += 4 * (s/ (2 * a + 1));
a is an int so the division result is an int.
A cast to double will fix it:
b += 4 * (s/ (2 * double(a) + 1));