Help making this code run faster for SPOJ - c

I've been doing a few of the challenges on the Sphere Online Judge (SPOJ), but I can't seem to get the second problem (the prime generator) to run within the time limit. How can the speed of the following code be increased?
#include <stdio.h>
#include <math.h>
int is_prime(int n);
void make_sieve();
void fast_prime(int n);
int primes[16000];
int main()
{
int nlines;
int m, n;
make_sieve();
scanf("%d", &nlines);
for (; nlines >= 1; nlines--) {
scanf("%d %d", &m, &n);
if (!(m % 2)) {
m++;
}
for ( ; m < n; m+=2) {
fast_prime(m);
}
printf("\n");
}
return 0;
}
/* Prints a number if it's prime. */
inline void fast_prime(int n)
{
int j;
for (int i = 0; ((j = primes[i]) > -1); i++) {
if (!(n % j)) {
return;
}
}
printf("%d\n", n);
}
/* Create an array listing prime numbers. */
void make_sieve()
{
int j = 0;
for (int i = 0; i < 16000; i++) {
primes[i] = -1;
}
for (int i = 2; i < 32000; i++) {
if (i % 2) {
if (is_prime(i)) {
primes[j] = i;
j++;
}
}
}
return;
}
/* Test if a number is prime. Return 1 if prime. Return 0 if not. */
int is_prime(int n)
{
int rootofn;
rootofn = sqrt(n);
if ((n <= 2) || (n == 3) || (n == 5) || (n == 7)) {
return 1;
}
if (((n % 2) == 0) || ((n % 3) == 0) || ((n % 5) == 0) || ((n % 7) == 0)) {
return 0;
}
for (int i = 11; i < rootofn; i += 2) {
if ((n % i) == 0) {
return 0;
}
}
return 1;
}

isprime() does not make use of the prime number table primes[].
Plus, implement a search of the primes array that will complete quickly using a binary search algorithm. The standard library has one.
To see where your time is spent in code you can use profiling
gcc example
gcc -p -g - o mycode mycode.c
===run the code--
gprof mycode

Currently, your problem isn't time limit. Its the fact that your program never print any numbers.
The most obvious error is that in fast_prime you are checking if n is divisible by prime[0], prime[1],... up to prime[k]. Even if n is prime, you won't print it, because n is somewhere in primes[], and so you'll get that n is divisible by some number...
To correct this, you need to check that n is divisible by some prime number up to the square root of n (this will also have the side effect of speeding up the code, as less numbers will be checked before deciding some number is a prime)
change fast_prime to
inline void fast_prime(int n)
{
int j;
int rootofn;
rootofn = sqrt(n);
for (int i = 0; ((j = primes[i]) > -1) && (j<rootofn); i++) {
if (!(n % j)) {
return;
}
}
printf("%d\n", n);
}

Related

Find all the decomposition of a number using only odd numbers and up to N numbers max

I want to find all the decompositions of a number using only odd numbers and up to N numbers max.
For example for the number 7 and N = 3, I can only get 1+1+5, 1+3+3, 7. I can't get 1+1+1+1+3 because it's greater then N.
They hint us to use backtracking.
I strated writing the code and I am stuck. If someone can explian to me how to solve this problem it will be great.
int T(int n, int k)
{
if (k == 0)
{
return;
}
int arr[N];
int f;
for (f = 0; f < N; f++)
{
arr[f] = 0;
}
int sum = 0;
int j = 1;
int i = 1;
int c = 0;
while (j < k) {
sum = sum + i;
arr[c] = i;
if (sum == n)
{
for (f = 0; f < N; f++)
{
if (arr[f] != 0)
{
printf("%d ", arr[f]);
}
}
printf("\n");
}
else if (sum > n)
{
arr[c] = 0;
sum = sum - i;
i = i - 2;
}
else
{
i = i + 2;
j++;
c++;
}
}
T(n, k - 1);
}
Please compile with warnings (-Wall) and fix all of them (-Werror helps make sure you do this). I didn't build your code, but int T(int n, int k) says it returns an int, yet the function code is void.
With backtracking, you can't print at each node because the current node in the graph might not actually lead to a solution. It's premature to commit anything to the result set until you actually reach it.
It's best not to print in functions that perform logical tasks anyway, but it can make the coding easier while developing the logic so I'll stick wiith it.
The backtracking suggestion is a good one. Here's the logic:
The "found result" base case is when n == 0 && k >= 0, if you're decrementing n and k and using them to represent the remaining value to reach the goal and the number of choices left. If you're incrementing variables to count up to n and k, that's fine too, in which case the base case is current_total == n && taken_so_far <= k.
Next, the "failure" base case is k < 0 || n < 0 because we've either overshot n or run out of numbers to take.
After that, the recursive case is, in English, "try taking each odd number i up to n, recursing on the possibility that i might be part of the solution". Per your spec, we don't accept any sequence of descending numbers which prunes the recursion tree a bit.
Here's the code; again, returning a result is an exercise. I'm using a k-sized array to store potential results, then dumping it to stdout only when a result was found.
#include <stdio.h>
#include <stdlib.h>
void odd_decomposition_search(
int n, const int k, int taken_length, int *taken
) {
if (n == 0 && taken_length <= k && taken_length > 0) {
for (int i = 0; i < taken_length - 1; i++) {
printf("%d+", taken[i]);
}
printf("%d\n", taken[taken_length-1]);
}
else if (n > 0 && taken_length < k) {
int i = taken_length ? taken[taken_length-1] : 1;
for (; i <= n; i += 2) {
taken[taken_length] = i;
odd_decomposition_search(n - i, k, taken_length + 1, taken);
}
}
}
void odd_decomposition(const int n, const int k) {
if (n <= 0 || k <= 0) {
return;
}
int taken[k];
odd_decomposition_search(n, k, 0, taken);
}
int main() {
int n = 7;
int k = 3;
odd_decomposition(n, k);
return 0;
}
If you're having trouble understanding the call stack, here's a visualizer you can run in the browser:
const oddDecomp = (n, k, taken=[]) => {
console.log(" ".repeat(taken.length), `[${taken}]`);
if (n === 0 && taken.length <= k && taken.length) {
console.log(" ".repeat(taken.length), "-> found result:", taken.join("+"));
}
else if (n > 0 && taken.length < k) {
for (let i = taken.length ? taken[taken.length-1] : 1; i <= n; i += 2) {
taken.push(i);
oddDecomp(n - i, k, taken);
taken.pop(i);
}
}
};
oddDecomp(7, 3);

How to find the nearest prime for a given number using for loop in C?

I really tried but still don't know what's wrong with my code.
#include <stdio.h>
int main()
{
int n;
scanf("%d", &n);
int minus, i, judge;
for (minus = 0, judge = 1; judge == 1; minus++, n -= minus) {
for (i = 2; i * i < n; i++) {
if (n % i == 0)
judge = 1;
else judge = 0;
}
if (judge == 1)
continue;
else break;
}
printf("%d\n", n);
return 0;
}
When I input 143, the output is 143 not 139.
However, when I input 11, the output is the correct answer 11.
The loop test is incorrect: for (i = 2; i * i < n; i++)
If n is the square of a prime number, the loop will stop just before finding the factor.
You should either use i * i <= n or i <= n / i.
Furthermore, you do not enumerate all numbers as you decrement n by an increasing value at each iteration.
Note also that the loop would not find the closest prime to n, but the greatest prime smaller than n, which is not exactly the same thing.
Here is a modified version:
#include <limits.h>
#include <stdio.h>
int isPrime(int n) {
if (n <= 2 || n % 2 == 0)
return n == 2;
for (int i = 3; i <= n / i; i += 2) {
if (n % i == 0)
return 0;
}
return 1;
}
int main() {
int n;
if (scanf("%d", &n) != 1)
return 1;
if (n <= 2) {
printf("2\n");
} else {
for (i = 0;; i++) {
if (isPrime(n - i))
printf("%d\n", n - i);
break;
}
if (n <= INT_MAX - i && isPrime(n + i))
printf("%d\n", n + i);
break;
}
}
}
return 0;
}

Finding the numbers that are palindromic in both base 2 and 10 and summing them up

I need to find the sum of all numbers that are less or equal with my input number (it requires them to be palindromic in both radix 10 and 2). Here is my code:
#include <stdio.h>
#include <stdlib.h>
int pal10(int n) {
int reverse, x;
x = n;
while (n != 0) {
reverse = reverse * 10 + n % 10;
n = n / 10;
}
if (reverse == x)
return 1;
else
return 0;
}
int length(int n) {
int l = 0;
while (n != 0) {
n = n / 2;
l++;
}
return l;
}
int binarypal(int n) {
int v[length(n)], i = 0, j = length(n);
while (n != 0) {
v[i] = n % 2;
n = n / 2;
i++;
}
for (i = 0; i <= length(n); i++) {
if (v[i] == v[j]) {
j--;
} else {
break;
return 0;
}
}
return 1;
}
int main() {
long s = 0;
int n;
printf("Input your number \n");
scanf("%d", &n);
while (n != 0) {
if (binarypal(n) == 1 && pal10(n) == 1)
s = s + n;
n--;
}
printf("Your sum is %ld", s);
return 0;
}
It always returns 0. My guess is I've done something wrong in the binarypal function. What should I do?
You have multiple problems:
function pal10() fails because reverse is not initialized.
function binarypal() is too complicated, you should use the same method as pal10().
you should avoid comparing boolean function return values with 1, the convention in C is to return 0 for false and non zero for true.
you should avoid using l for a variable name as it looks very similar to 1 on most constant width fonts. As a matter of fact, it is the same glyph for the original Courier typewriter font.
Here is a simplified and corrected version with a multi-base function:
#include <stdio.h>
#include <stdlib.h>
int ispal(int n, int base) {
int reverse = 0, x = n;
while (n > 0) {
reverse = reverse * base + n % base;
n = n / base;
}
return reverse == x;
}
int main(void) {
long s = 0;
int n = 0;
printf("Input your number:\n");
scanf("%d", &n);
while (n > 0) {
if (ispal(n, 10) && ispal(n, 2))
s += n;
n--;
}
printf("Your sum is %ld\n", s);
return 0;
}
in the function pal10 the variable reverse is not initialized.
int pal10(int n)
{
int reverse,x;
^^^^^^^
x=n;
while(n!=0)
{
reverse=reverse*10+n%10;
n=n/10;
}
if(reverse==x)
return 1;
else
return 0;
}
In the function binarypal this loop is incorrect because the valid range of indices of an array with length( n ) elements is [0, length( n ) - 1 ]
for(i=0;i<=length(n);i++)
{
if(v[i]==v[j])
{
j--;
}
else
{
break;
return 0;
}
}
And as #BLUEPIXY pointed out you shall remove the break statement from this else
else
{
break;
return 0;
}

Sieve of Eratosthenes and his primes

This is my code:
#include <stdio.h>
int main() {
int number;
int prime[200000] = { 0 };
int i = 0;
int j = 0;
int number1[200] = { 0 };
int t = 0;
int count = 0;
int newprime2[200][200];
int counter[200] = { 0 };
int square;
int count1;
while ((scanf("%d", &number) == 1 ) && (number != 0)) {
number1[count] = number;
++count;
}
count1 = count;
for (count = 0; count < count1; ++count) {
if (number1[count] < 0) {
fprintf(stderr, "Error: Invalid input!\n");
return 100;
break;
}
for (i = 0; i < number1[count]; i++) {
prime[i] = i;
}
for (i = 2; (i < (number1[count])); i++) {
if (prime[i] != 0) {
for (j = 2; (j < (number1[count])); j++) {
{
prime[j*prime[i]] = 0;
if (prime[i] * j > (number1[count]))
break;
}
}
}
}
t = 0;
for (i = 2; i < number1[count]; ++i) {
if ((prime[i] != 0) && (number1[count] % prime[i] == 0)) {
newprime2[count][t] = prime[i];
++t;
}
}
printf("\n");
printf("%i is made out of these primes\n", number1[count]);
counter[count] = 0;
square = 0;
for (i = 0; i < t; ++i) {
while (number1[count] % newprime2[count][i] == 0) {
number1[count] = number1[count] / newprime2[count][i];
square++;
}
counter[count]++;
/* if number isn't made out of any of these primes*/
if (!newprime2[count][i]) { /*Why is this not working?*/
printf("%i ", number1[count]);
}
if (counter[count] == 1) {
printf("%i^%d ", newprime2[count][i], square);
} else {
printf("* %i^%d ", newprime2[count][i], square);
}
square = 0;
}
}
printf("\n");
return 0;
}
For example, my input is: 1 11 120 8 0
Output looks like this:
1 is made out of these primes
11 is made out of these primes
120 is made out of these primes
2^3 * 3^1 * 5^1
8 is made out of these primes
2^3
But Output should looks like this:
1 is made out of these primes
1
11 is made out of these primes
11
...
Statement (!newprime2[count][i]) means that this array is empty right? So why it isn't working? And why I even can't use gcc -pedantic -Wall -Werror -std=c99 -O3 ? Can someone help me?
See this part of your code:
t = 0;
for (i = 2; i < number1[count]; ++i){
if ((prime[i]!=0) && (number1[count] % prime[i]==0)){
newprime2[count][t] = prime[i];
++t;
}
If number1[count] is 1, then the body of the for loops will not execute, sot will keep its value (0). Consequently the body of the next loop
for (i=0; i < t; ++i){
will not execute, too.
For number 11 the body of this loop will execute but it will do nothing as the condition in the if statement will be always false. So it results to the same problem - t will keep its value 0 with the same consequence.
The line
if (!newprime2[count][i])
is not reached if t==0 before the for-loop and that is the case if the input is prime or unity. Just check t and end there if it is zero.
Or check earlier if it is unity or it is in prime already.
I cannot repeat your problems with gcc -pedantic -Wall -Werror -std=c99 -O3.
Your algorithm is both too complicated and approximate:
You do not need to perform a sieve to factorize the numbers, you can just enumerate divisors, composite divisors will have a non zero remainder because their prime factors will have been removed already.
The sieve is incomplete: you go to 200000 which would be overkill if int type is 32 bits (46341 would suffice) and would be too small if int is 64 bits.
Here is a simplified version:
#include <stdio.h>
int main(void) {
int number, i, p, n, factors, count;
int numbers[200];
for (count = 0; count < 200 && scanf("%d", &number) == 1; count++) {
if (number == 0)
break;
if (number < 0) {
fprintf(stderr, "Error: Invalid input!\n");
return 100;
}
numbers[count] = number;
}
for (i = 0; i < count; i++) {
number = numbers[i];
printf("%d is made out of these primes\n", number);
factors = 0;
for (p = 2; p * p <= number; p += 1 + (p & 1)) {
if (number % p == 0) {
n = 0;
factors++;
do {
number /= p;
n++;
} while (number % p == 0);
if (n == 1)
printf("%d ", p);
else
printf("%d^%d ", p, n);
}
}
if (factors == 0 || number != 1)
printf("%d", number);
printf("\n");
}
return 0;
}

Why this reverse function can not work in the for loop?

#include <stdio.h>
#include <math.h>
int prime (long n);
long reverse(long n);
int main(void)
{
long n;
long i, j;
puts("Enter n dight number, and we will help you find symmetrical prime number");
scanf("%ld", &n);
for (i = 11; i < (pow(10, n) - 1); i+= 2)
{
if (prime(i))
{
j = reverse(i);
if (i == j)
{
printf("%ld\n", i);
}
}
}
}
int prime (long n) //estimate whether the number n is primer number
{
int status = 0;
int j;
//1 is prime, 0 is not
if (n % 2 == 0 || n == 3)
{
if (n == 2)
status = 1;
if (n == 3)
status = 1;
else
{
n++;
status = 0;
}
}
else
{
j = 3;
while (j <= sqrt(n))
{
if (n % j == 0)
{
status = 0;
break;
}
else
status = 1;
j+= 2;
}
}
return status;
}
long reverse(long n) //reverse a number
{
int i, j, x;
long k, sum;
int digit = 0;
int ar[1000];
while (n > 0)
{
k = n;
n = n / 10;
x = (k - n*10);
digit++;
ar[digit] = x;
}
for (i = 1,j = digit - 1; i <= digit; i++, j--)
{
sum += ar[i] * pow(10, j)
}
return sum;
}
I build a reverse function in order to reverse numbers, for example, 214, to 412.
This function works fine in individual number, for instance, I type reverse(214), it return 412, which is good. But when I combine reverse() function with for loop, this function can not work... it produces some strange number...
so How can I fix this problem?
The reverse function is extremely complicated. The better way to go about it would be:
long reverse (long n)
{
long result = 0;
while (n != 0)
{
result *= 10;
result += n % 10;
n /= 10;
}
return result;
}
I think the problem in your code is that in the following segment
digit++;
ar[digit] = x;
you first increment the position then assign to it, thus leaving ar[0] unintialized.
How can I fix this problem?
You need to initialize sum
long k, sum = 0;
^
See the code from #Armen Tsirunyan for a simpler approach.

Resources