Sieve of Eratosthenes C++ Infinite Loop - c++

So, I've been working through a problem in Bjarne Stroustrup's Programming: Principles and Practices Using C++ for my own benefit, and this problem has stumped me for a couple of days now.
I'm supposed to implement the classic Sieve of Eratosthenes algorithm with the tools learned by chapter 4 (that's not a lot) and this is what I have so far:
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main()
{
int p = 2;
int n = 0;
vector<int> nums{ 1, 1 };
cout << "Enter an integer greater than 1:\n";
cin >> n;
for (int i = 2; i <= n; ++i)
nums.push_back(0);
while (p < sqrt(n))
{
for (int i = 2; (i*p) <= n; ++i)
{
nums[i*p] = 1;
}
for (int i = (p+1); i <= n; ++i)
{
if (nums[i] == 0)
{
p = i;
break;
}
}
}
for (int i = 0; i <= n; ++i)
{
if (nums[i] == 0)
cout << i << '\n';
}
return 0;
}
This code is SOOO close to working but no cigar. It only prints the prime numbers after and including 5, it does not print 2 or 3. I know that the problem is due to the fact that my marking loop is marking nums[2] and nums[3], so I tried to add the following line of code to insure that 2 and 3 were unmarked, because they were used as the p starting values:
nums[p] = 0;
I put that line in-between the two for-loops nested within the while-loop. I have no idea how, but that somehow causes an infinite loop that I've tried for hours to fix. I'm really at my wit's end here.
NOTE: I've been testing this with n = 23.

So, after fixing your first loop starting point, the issue is the next loop.
Because the next loop always starts at 0 and looks for the next prime number, it is going to always find 2, and that will cause an infinite loop.
To solve this issue, start your search for the next prime, from the previous value:
for(int i = p + 1; i <= n; ++i)

Related

Issues with Sieve of Eratosthenes

I picked up "Programming Principles and Practice using C++", and was doing an early problem involving the Sieve of Eratosthenes, and I'm having unexpected output, but I cannot pin down exactly what the problem is. Here is my code:
#include <iostream>
#include <vector>
int main()
{
std::vector<int> prime;
std::vector<int> nonPrime;
int multiple = 0;
for(int i = 2; i < 101; i++) //initialized to first prime number, i will
// be the variable that should contain prime numbers
{
for(int j = 0; j < nonPrime.size(); j++) //checks i against
// vector to see if
// marked as nonPrime
{
if(i == nonPrime[j])
{
goto outer;//jumps to next iteration if number
// is on the list
}
}
prime.push_back(i); //adds value of i to Prime vector if it
//passes test
for(int j = i; multiple < 101; j++) //This loop is where the
// sieve bit comes in
{
multiple = i * j;
nonPrime.push_back(multiple);
}
outer:
;
}
for(int i = 0; i < prime.size(); i++)
{
std::cout << prime[i] << std::endl;
}
return 0;
}
The question only currently asks me to find prime numbers up to 100 utilizing this method. I also tried using this current 'goto' method of skipping out of a double loop under certain conditions, and I also tried using a Boolean flag with an if statement right after the check loop and simply used the "continue;" statement and neither had any effect.
(Honestly I figured since people say goto was evil perhaps it had consequences that I hadn't foreseen, which is why I tried to switch it out) but the problem doesn't call for me to use modular functions, so I assume it wants me to solve it all in main, ergo my problem of utilizing nested loops in main. Oh, and to further specify my output issues, it seems like it only adds multiples of 2 to the nonPrime vector, but everything else checks out as passing the test (e.g 9).
Can someone help me understand where I went wrong?
Given that this is not a good way to implement a Sieve of Eratosthenes, I'll point out some changes to your code to make it at least output the correct sequence.
Please also note that the indentation you choose is a bit misleading, after the first inner loop.
#include <iostream>
#include <vector>
int main()
{
std::vector<int> prime;
std::vector<int> nonPrime;
int multiple = 0;
for(int i = 2; i < 101; i++)
{
// you can use a flag, but note that usually it could be more
// efficiently implemented with a vector of bools. Try it yourself
bool is_prime = true;
for(int j = 0; j < nonPrime.size(); j++)
{
if(i == nonPrime[j])
{
is_prime = false;
break;
}
}
if ( is_prime )
{
prime.push_back(i);
// You tested 'multiple' before initializing it for every
// new prime value
for(multiple = i; multiple < 101; multiple += i)
{
nonPrime.push_back(multiple);
}
}
}
for(int i = 0; i < prime.size(); i++)
{
std::cout << prime[i] << std::endl;
}
return 0;
}

What does this variable do?

One day, Twilight Sparkle is interested in how to sort a sequence of
integers a1, a2, ..., an in non-decreasing order. Being a young
unicorn, the only operation she can perform is a unit shift. That is,
she can move the last element of the sequence to its beginning:
a1, a2, ..., an → an, a1, a2, ..., an - 1. Help Twilight Sparkle to
calculate: what is the minimum number of operations that she needs to
sort the sequence?
Input
The first line contains an integer n (2 ≤ n ≤ 105). The second
line contains n integer numbers a1, a2, ..., an (1 ≤ ai ≤ 105).
Output
If it's impossible to sort the sequence output -1. Otherwise
output the minimum number of operations Twilight Sparkle needs to sort
it.
Examples
input
2
2 1
output
1
input
3
1 3 2
output
-1
input
2
1 2
output
0
Above is the problem and now I am confused because the solution down there used a variable called "s" and played around it for some reason but I don't know why was that variable used, if someone can tell me I'll be thankful.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n, s, v(0);
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 0; i < n - 1; i++) if (a[i] > a[i + 1]) s = i, v++;
if (a[n - 1] > a[0]) s = n - 1, v++;
if (v == 0) cout << 0 << endl;
else if (v > 1) cout << -1 << endl;
else cout << n - 1 - s << endl;
return 0;
}
Now here is my own solution, it works and everything except on a 10^5(and around that) size array but the question time limit is only 1000 ms, and mine exceeds that limit due to the nested loops making it go over O(10^8) which is 1000 ms on their systems.
#include <bits/stdc++.h>
#define fl(i,n) for(int i = 0; i < n; i++)
#define ll long long
#define nl endl
#define pb push_back
#define mp make_pair
#define PII pair<int,int>
#define EPS 1e-9
#define INF 1e9
using namespace std;
bool check(int a[], int n){
for(int i = 0; i < n-1; i++){
if(a[i] <= a[i+1]) continue;
return false;
}
return true;
}
int main()
{
int n;
cin >> n;
int a[n]; //is out of standard i know but it's accepted in the contest's compiler so we just use it
for(int i = 0; i < n; i++){
cin >> a[i];
}
if(check(a,n)){
cout << 0;
return 0;
}
int ret = 0;
for(int i = 0; i < n-1; i++){
ret++;
for(int j = n-1; j > 0; j--)
a[j] ^= a[j-1] ^= a[j] ^= a[j-1]; //is xor swap
if(check(a,n)){
cout << ret;
return 0;
}
}
cout << -1;
return 0;
}
PS: I TRACED the solution's code and even if I get the correct answers I simply don't know what it refers to.
The other person's implementation relies on an algorithmic insight. The only way a sequence can be sorted by moving back to front is if the sequence is made of two already-sorted sections. Then, the goal is to check how many unsorted discontinuities exist, and where they are. That's what s appears to be used for: the index of the (last) discontinuity of the sequence. v is the count of discontinuities.
If there are 0, it's already sorted. If more than 1, it's unsortable. If it's exactly one, then you can easily figure out how many shifts you need to perform to pull the discontinuity back to the front, using it's location (s) in the original sequence.
The only extra line of code is the special case of checking for the discontinuity around end of the sequence.
My recommendation: Generate a larger set of test sequences, and print v and s for each one.

For a given sequence of n numbers, find the substring with a maximum total sum with the lowest computational complexity as possible

Task:For a given sequence of n numbers, find the substring with a maximum total sum. I created I code in C++ which give correct answers. I would like to know is there any possibility to solve this task with lower computational complexity?
Example input:
20
8973
-4625
-2038
3405
-7004
-9853
-361
3294
4036
8767
1711
-3100
2139
-4993
-9572
3789
2472
-6170
5408
2200
output:
17808
My actual code:
#include<iostream>
#include<cmath>
#include<vector>
#include <algorithm>
using namespace std;
typedef long long int lint;
int main()
{
lint t = 0;
cin >> t;
vector<lint> Ar;
bool st = false;
for (lint i = 0; i < t; i++)
{
lint n = 0;
cin >> n;
if (st == true)Ar.push_back(n);
else if (n>0 && st == false)
{
Ar.push_back(n);
st = true;
}
}
if (Ar.size() == 0)
{
cout << "0" << endl;
}
else
{
vector<lint> Adding;
for (std::size_t i = 0; i < Ar.size(); i++)
{
if (Ar[i] > 0)
{
Adding.push_back(i);
}
}
vector<lint> D;
for (std::size_t j = 0; j < Adding.size(); j++)
{
lint s = 0;
for (std::size_t i = Adding[j]; i < Ar.size(); i++)
{
if (Ar[i] > 0)
{
s += Ar[i];
D.push_back(s);
}
else
{
s += Ar[i];
}
}
}
vector<lint>::const_iterator it2;
// Find max element in the vector
it2 = max_element(D.begin(), D.end());
cout << *it2 << endl;
}
return 0;
}
The best computational complexity to solve this task is linear. Your code on the other hand is not linear and therefor the answer to your question is - yes it is possible to solve the problem with better complexity.
The problem you are solving is known as Maximum subarray problem and is quite famous.
It looks that you went straight into writing code.
The first step would be to think about the problem.
The optimal sequence might include the first number 20. If you examine the numbers from the start, where might the sequence end with an optimal result if it starts with 20? And at which point could you say that any longer sequence that is optimal cannot contain the number 20?
If you look at the sequence and examine it one by one, you will see that 20+8973 might be optimal. Up to 3405 is not optimal but might be the start of an optimal sequence. But with the -9853 it is obvious that an optimal sequence other than 20+8973 must start with the 3294 or later. (Ask yourself why, then turn it into an algorithm).

C++ algorithm optimization: find K combination from N elements

I am pretty noobie with C++ and am trying to do some HackerRank challenges as a way to work on that.
Right now I am trying to solve Angry Children problem: https://www.hackerrank.com/challenges/angry-children
Basically, it asks to create a program that given a set of N integer, finds the smallest possible "unfairness" for a K-length subset of that set. Unfairness is defined as the difference between the max and min of a K-length subset.
The way I'm going about it now is to find all K-length subsets and calculate their unfairness, keeping track of the smallest unfairness.
I wrote the following C++ program that seems to the problem correctly:
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
int unfairness = -1;
int N, K, minc, maxc, ufair;
int *candies, *subset;
void check() {
ufair = 0;
minc = subset[0];
maxc = subset[0];
for (int i = 0; i < K; i++) {
minc = min(minc,subset[i]);
maxc = max(maxc, subset[i]);
}
ufair = maxc - minc;
if (ufair < unfairness || unfairness == -1) {
unfairness = ufair;
}
}
void process(int subsetSize, int nextIndex) {
if (subsetSize == K) {
check();
} else {
for (int j = nextIndex; j < N; j++) {
subset[subsetSize] = candies[j];
process(subsetSize + 1, j + 1);
}
}
}
int main() {
cin >> N >> K;
candies = new int[N];
subset = new int[K];
for (int i = 0; i < N; i++)
cin >> candies[i];
process(0, 0);
cout << unfairness << endl;
return 0;
}
The problem is that HackerRank requires the program to come up with a solution within 3 seconds and that my program takes longer than that to find the solution for 12/16 of the test cases. For example, one of the test cases has N = 50 and K = 8; the program takes 8 seconds to find the solution on my machine. What can I do to optimize my algorithm? I am not very experienced with C++.
All you have to do is to sort all the numbers in ascending order and then get minimal a[i + K - 1] - a[i] for all i from 0 to N - K inclusively.
That is true, because in optimal subset all numbers are located successively in sorted array.
One suggestion I'd give is to sort the integer list before selecting subsets. This will dramatically reduce the number of subsets you need to examine. In fact, you don't even need to create subsets, simply look at the elements at index i (starting at 0) and i+k, and the lowest difference for all elements at i and i+k [in valid bounds] is your answer. So now instead of n choose k subsets (factorial runtime I believe) you just have to look at ~n subsets (linear runtime) and sorting (nlogn) becomes your bottleneck in performance.

Prime number finder cannot find prime, stops after 7

So I made a simple prime number finder for the numbers between 3 and 200. It has to use a boolean variable, just fyi. No errors occur. output is:
The prime numbers between 3 and 200 are:
3
5
7
Why does it not keep going? I have drawn it out on paper time and again and cannot find my logic error.
In addition; I wrote this out by hand because I do not know how to get the contents of my file. It exists on a remote host which I do not have root access to. Is there a better way to copy the file?
#include <iostream>
using namespace std;
int main()
{
int count=0;
cout<<"The prime numbers between 3 and 200 are: "<<endl;
for (int i=3;i<=200;i++)
{
for (int j=2;j<i;j++)
{
bool ptest=i%j;
if (!ptest)
{
break;
}
else if (ptest)
{
count=count+1;
if (count==(i-2))
cout<<i<<endl;
}
}
}
}
You forgot to set count back to 0 after using it in the j loop. Move the line:
int count = 0;
to be inside the first for loop. Then your program works correctly (although as msw indicated, it is not the most efficient technique!)
Some things to consider:
You don't need to consider any even numbers in your code.
You have some logic errors in your code. The value of count needs to be checked after the second for loop. count needs to be reset before the second for loop begins.
You can stop immediately after you find the number is not prime in the inner loop instead of continuing on. You can just use a flag isPrime instead of counting.
Here's a version of the code that works for me:
#include <iostream>
using namespace std;
int main()
{
cout << "The prime numbers between 3 and 200 are: " <<endl;
for (int i=3; i <= 200; i += 2) {
bool isPrime = true;
for (int j=3; j < i; j += 2) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime)
{
cout << i << endl;
}
}
}
You don't have to loop till j reach i, instead you can check if j < sqrt(i) ,i.e. write in the second for loop: for (int j=3; j*j<=i; j+=2)