Counting paths through a grid: can this algorithm be improved? - c

I'm a novice without any knowledge of algorithm optimization.
I'm trying to write a code that counts the number of paths on a 20x20 grid, or lattice, from its top-left corner to its bottom-right one, only being able to move down and to the right. For example, the number of paths on a 2x2 grid would be 6:
My (very not optimal) idea is: any sequence of 2*20 moves such that I move down as many times as I move to the right, will get me to the final point.
So I would generate any possible sequence of down and right moves, and then count those that respect that criteria.
I wanted to represent this sequence with a 40-bits binary number, where 0s and 1s represent the two possible moves.
I code in C and didn't find a way to deal with binary numbers, so I use an array of 40 ints.
So by starting from int n = {0,0,...,0} I check that number of zeros = number of ones, if so I increase a counter. I then "sum 1" to this array as I would do to a binary number, and I repeat until I get to {1,1,...,1}.
The code takes 7 seconds for 13x13 grids, up to 8 minutes for a 16x16 grid, and I'd need weeks to run it for a 20x20 grid. Is there any way that this code can be speeded up? Or is this an overall silly strategy to solve the problem? The code is the following:
#include <stdio.h>
#include <stdlib.h>
int ispath(int* n, int siz){
//returns 1 if n has number of 1s = number of 0s, returns 0 otherwise
int n0,n1;
n0=0; n1=0;
for(int i=0;i<siz;i++){
if(n[i]==0) n0++;
else n1++;
}
if(n1==n0) return 1;
else return 0;
}
int risen(int* n,int siz){
//"sums" 1 to the binary number represented by n
//returns just to break from function
for(int i =siz-1;i>=0;i--){
if(n[i]==0){
n[i]=1; return 1;
}else n[i]=0;
}
}
int sumn(int* n, int siz){
int sum=0;
//sum elements of n, to check when n=11...1 and stop the while loop in main
for(int i =0;i<siz;i++) sum+=n[i];
return sum;
}
int main(){
int n[] = {0,0,0,0};//NXN lattice requires n with 2N starting zeros. This n represents 2x2 lattice
int sizen = sizeof(n)/sizeof(n[0]);
long long cnt = 0;
while(sumn(n,sizen)<sizen){
if(ispath(n,sizen)){
cnt++;
}
risen(n,sizen);
}
printf("Number of paths: %lli",cnt);
}

Related

How to optimize/ make this c code even faster?

I need to optimize this c code in order for it to run as fast as possible. I am quite new to code optimization in general. What should I begin with?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char*argv[]) {
int n, i, flag;
int sumOfPrimeNumbers; //sum of prime numbers
sumOfPrimeNumbers = 0;
do {
flag = 0;
scanf("%d", &n);
for(i=2;i < n;i++)
{
if(n%i==0) {
flag=1; // flag all non-prime numbers
break;
}
}
if(flag==0) {
sumOfPrimeNumbers = sumOfPrimeNumbers + n; // sum prime numbers
}
} while (n != 0);
printf("%d\n", sumOfPrimeNumbers);
return 0;
}
For small values of n (maybe values less than 66536?) you can use a table of precomputed answers, like "printf("%d\n", table[n]);".
For larger values you can split n into "zone" and "offset in zone", like "zone = n / zone_size; offset = n % zone_size;" and then use "zone" as an index into a precomputed table to determine an initial starting point (and skip a huge amount of work, like "sumOfPrimeNumbers = zoneStartTable[n / zone_size;"). The "offset in zone" part can be used with Sieve of Eratosthenes; which means that it's nicer for "zone_size" to be the product of the smallest primes (e.g. maybe like "zone_size = 2 * 3 * 5 * 7 * 11 * 13 * 17;") because that makes it a little easier to create a Sieve of Eratosthenes from a non-zero starting point.
For this approach to work you will actually need 2 sieves - one to find primes from 1 to "sqrt(n)" so that you can mark multiples of those primes as "not prime" in the second sieve (which will contain values from "zone * zone_size" to n). This process can be accelerated by recognizing that the sieve for the smallest primes (that you used to determine "zone_size") create a pattern that repeats every "zone_size" numbers, and that pattern can be predetermined and then copied into both of the sieves to initialize the sieves, allowing you to skip marking the smallest primes in both sieves.
Improve the algorithm. Avoid premature optimizations
Rather than test up to n, search to the square root of n
// for(i=2;i < n;i++)
for (i=2; i <= n/i; i++)
Sieve of Eratosthenes
Form a list of found primes {2,3,5} and only test against those. As a new prime is found, append it to the list.
Many other optimizations possible.

How do I write a program to find the number of binary strings of length n containing exactly three 1s, all consecutive

I've followed a dynamic programming approach here.
dp(i,x) :denotes number of strings of length i with x consecutive 1s in position i + 1 to i + x.
n here is the length of the bit string taken as input from the user
However, I think I'm counting strings that have more than 3 consecutive ones as well maybe?
EDIT: Just to clarify
I am looking for strings with exactly 3 1s. For eg: 111000 is a valid string whereas 1110101111 and 10101000 are not.
#include<stdio.h>
#include<stdlib.h>
int solve(int i,int x,int **arr)
{
if(i<0)
return x==3;
if(arr[i][x]!=-1)
return arr[i][x];
arr[i][x] = solve(i-1,0,arr);
arr[i][x]+=solve(i-1,x+1,arr);
return arr[i][x];
}
int main()
{
int n;
scanf("%d",&n);
int **arr = (int**)malloc(n*sizeof(int*));
for(int i=0;i<n;i++)
arr[i] = (int*)malloc(4*sizeof(int));
for(int i=0;i<n;i++)
for(int j=0;j<4;j++)
arr[i][j]=-1;
for(int i=0;i<n;i++)
arr[i][3] = (1<<(i+1));
printf("%d",solve(n-1,0,arr));
return 0;
}
Your DP state [i][x] means - number of binary strings of length i that have x bits in ending, so you're also counting strings like 11110111.
You need to take into account groups of 3 that are not suffixes, for that you can update dp state as follows: [i][x][y] - number of binary strings of length i that have x bits in ending and a maximum y consecutive bits.
Code modification is quite minimal:
int solve(int i,int x, int y, int ***arr)
{
if(y > 3) return 0;
if(i<0) return y==3;
if(arr[i][x][y]!=-1) return arr[i][x][y];
arr[i][x][y] = solve(i-1,0,y,arr);
arr[i][x][y]+=solve(i-1,x+1,max(x+1,y),arr);
return arr[i][x][y];
}
I'm not sure if I have well understood your question:
The question is not : "What are all the binary numbers, containing exactly three consecutive ones?", but just: "What's the number of the binary numbers, containing exactly three consecutive ones?".
If you are just interested in the number, you might just calculate it by heart:
1110xxxxx (total length : N) : amount of such numbers : 2^(N-4) [(N-4) digits with 2 possibilities)]
xx01110xx (total length : N) : amount of such numbers : 2^(N-5)*(N-5)
[(N-5) digits with 2 possibilities]
[(N-5) places to put the '01110']
xxxxx0111 (total length : N) : amount of such numbers : 2^(N-4) [(N-4) digits with 2 possibilities]
Solution : 2*2^(N-4) + 2^(N-5)*(N-5)
(I didn't check completely, forgive me if this contains errors)
If you're not sure that you really need to generate all of them, then doing the calculation might actually be a better (and much faster) solution.

why < is much faster than !=?

Problem : Consider the following algorithm to generate a sequence of
numbers. Start with an integer n. If n is even, divide by 2. If n is
odd, multiply by 3 and add 1. Repeat this process with the new value
of n, terminating when n = 1. The input will consist of a series of
pairs of integers i and j, one pair of integers perline. All integers
will be less than 1,000,000 and greater than 0.
For each pair of
input integers i and j, output i, j in the same order in which they
appeared in the input and then the maximum cycle length for integers
between and including i and j. These three numbers should be separated
by one space, with all three numbers on one line and with one line of
output for each line of input.
sample input :
1 10
sample output:
1 10 20
so i wrote this :
#include <stdio.h>
#include <string.h>
struct line{int in1;int in2;int result;};
int cycle(int in);
int main(int argc, char *argv[]) {
int cycle(int in);
char c;
int firstIn=0;
struct line l[500] ;
int pointer=0;
while(2<3){
l[pointer].in1=0;
l[pointer].in2=0;
scanf("%u %u",&l[pointer].in1,&l[pointer].in2);
if(l[pointer].in1<1||l[pointer].in2<1){
break;
}
int maxCyc=0;
int j,m;
int min,max;
if(l[pointer].in1>l[pointer].in2){
max=l[pointer].in1;
min=l[pointer].in2;
}
else{
max=l[pointer].in2;
min=l[pointer].in1;
}
for(j=min;j<=max;j++){
m = cycle(j);
if(m>maxCyc)
maxCyc=m;
}
l[pointer].result=maxCyc;
printf("%d %d %d\n",l[pointer].in1,l[pointer].in2,l[pointer].result);
pointer++;
}
}
int cycle(int in){
int cyc = 1;
while(in>1){
if(in%2==0){
cyc++;
in=in/2;
}
else{
cyc++;
in=in*3+1;
}
}
return cyc;
}
Its completly ok but when you change while(in>1) in cycle method to while(in!=1) it gets much more slower. my question is why?!
Time when its while(in>1) : 0.683 sec
and when its while(in!=1) : I waited more than 5 min nothing
happened yet :)
for input : 1 1000000
there is no infinite loop or something because in cant get below 1 at all(for that it must be already 1) .
Best regards
When you call cycle with the input value 113383, the process eventually sets n to
827370449, and 3*827370449+1 is 2482111348, which is greater than the maximum signed int and is interpreted as -1812855948. So there's your first negative number where there should be no negative number.
If this process then eventually sets n to -2, it will loop infinitely between -2 and -1 from then on. There may be other loops I haven't considered.
If you were to use an unsigned int, there is a possibility (I haven't checked) that this too will overflow eventually, which will not result in a negative value but will result in an incorrect value, invalidating your results.
No matter what integer representation you use, it would probably be a good idea to compare n with (maximum-1)/3 at the top of each loop, where maximum is the largest possible positive value of your integer type, just to be sure you do not overflow.
As you told me it was a simple overflow problem thx everyone.
max int value is 2,147,483,647; So when i changed int cycle(int in) to int cycle(long long int in) my problem was solved.
i also figured it out that my first answer with while(in>1) was wrong.
When an integer overflow occurs,the value will go below 0 .That was the reason while(in!=1) was an infinte loop.
I was really tired that i didn't figure it out by myself. sorry for that :)

Reducing memory usage when designing a sieve of eratosthenes in C

I'm trying to design a sieve of eratosthenes in C but I've run into two strange problems which I can't figure out. Here's my basic program outline. Ask users to set a range to display primes from. If the range minimum is below 9, set the minimum as 9. Fill an array with all odd numbers in the range.
1) I'm trying to reduce memory usage by declaring variable size arrays like so:
if (max<=UINT_MAX)
unsigned int range[(max-min)/2];
else if (max<=ULONG_MAX)
unsigned long int range[(max-min)/2];
else if (max<=ULLONG_MAX)
unsigned long long int range[(max-min)/2];
Why doesn't this compile? Variables min and max are declared as ints earlier and limits.h is included. I've commented out the selection structure and just declared unsigned long long int range[(max-min)/2]; for now which compiles and works for now.
2) My code runs but it sometimes marks small primes as non primes.
#include<stdio.h>
#include<limits.h>
void prime(int min, int max)
{
int i, f=0;
//declare variable size array
/*if (max<=(int)UINT_MAX)
unsigned int range[(max-min)/2];
else if (max<=(int)ULONG_MAX)
unsigned long int range[(max-min)/2];
else if (max<=(int)ULLONG_MAX)*/
unsigned long long int range[(max-min)/2];
//fill array with all odd numbers
if (min%2==0)
{
for (i=min+1;i<=max;i+=2)
{
range[f]=i;
f+=1;
}
}
else
{
for (i=min;i<=max;i+=2)
{
range[f]=i;
f+=1;
}
}
//assign 0 to cell if divisible by any number other than itself
for (i=3;i<=sqrt(max);++i)
{
for (f=0;f<=((max-min)/2);f++)
{
if (range[f]%i==0 && f!=i)
range[f]=0;
}
}
//troubleshoot only: print full range
for (f=0;f<=((max-min)/2);f++)
{
printf("ALL: %d / %d\n", f, range[f]);
}
//display all primes
if (min==9) /*print primes lower than 9 for ranges where min<9*/
printf("2\n3\n5\n7\n");
for (f=0;f<=((max-min)/2);f++) /*print non 0 numbers in array*/
{
if (range[f]!=0)
printf("%d\n", range[f]);
}
}
int main(void)
{
int digits1, digits2;
printf("\n\n\nCalculate Prime Numbers\n");
printf("This program will display all prime numbers in a given range. \nPlease set the range.\n");
printf("Minimum: ");
scanf("%d", &digits1);
if (digits1<9)
digits1=9;
printf("Maximum: ");
scanf("%d", &digits2);
printf("Calculating...");
printf("All prime numbers between %d and %d are:\n", digits1, digits2);
prime(digits1, digits2);
getchar();
getchar();
}
For example, if digits=1 and digits2=200 my program outputs all primes between 1 and 200 except 11 and 13. 11 and 13 are sieved out and I can't figure out why this happens to more and more low numbers as digits2 is increased.
3) Finally, is my sieve a proper sieve of eratosthenes? It kind of works but I feel like there is a more efficient way of sieving out non primes but I can't figure out how to implement it. One of my goals for this program is to be as efficient as possible. Again, what I have right now is:
//assign 0 to cell if divisible by any number other than itself
for (i=3;i<=sqrt(max);++i)
{
for (f=0;f<=((max-min)/2);f++)
{
if (range[f]%i==0 && f!=i)
range[f]=0;
}
}
Thanks for reading all of that! I'm sorry for posting yet another sieve of eratosthenes related question and thank you in advance for the help!
No, it is not a proper sieve of Eratosthenes. No testing of remainders is involved in the sieve of Eratosthenes algorithm, Wikipedia is real clear on this I think. :) The whole point to it is to avoid the trial divisions, to get the primes for free, without testing.
How? By generating their multiples, from every prime that we identify, in ascending order one after another.
The multiples of a prime p are: 2p, 2p + p, 2p + p + p, ...
The odd multiples of a prime p are: 3p, 3p + 2p, 3p + 2p + 2p, ...
As we enumerate them, we mark them in the sieve array. Some will be marked twice or more, e.g. 15 will be marked for 3 and for 5 (because 3 * 5 == 5 * 3). Thus, we can start enumerating and marking from p2:
for( i=3; i*i < n; i += 2 )
if( !sieve[i] ) // if `i` is not marked as composite
for( j = i*i; j < n; j += 2*i )
{
sieve[j] = 1; // 1 for composite, initially all are 0s
}
The key to the sieve is this: we don't store the numbers in the array. It is not an array of INTs; it is an array of 1-bit flags, 0 or 1 in value. The index of an entry in the sieve array signifies the number for which the sieve holds its status: marked, i.e. composite, or not yet marked, i.e. potentially prime.
So in the end, all the non-marked entries signify the primes. You will need to devise an addressing scheme of course, e.g. an entry at index i might correspond to the number a + 2*i where a is the odd start of the range. Since your range starts at some offset, this scheme is known as offset sieve of Eratosthenes. A skeleton C implementation is here.
To minimize the memory use, we need to treat our array as a bit array. In C++ e.g. it is easy: we declare it as vector<bool> and it is automatically bit-packed for us. In C we'll have to do some bit packing and unpacking ourselves.
A word of advice: don't go skimpy on interim variables. Name every meaningful entity in your program. There shouldn't be any (max-min)/2 in your code; but instead define width = max - min and use that name. Leave optimizations in the small to the compiler. :)
To your first question: it's a scope thing. Your code is equivalent to
if (max<=UINT_MAX)
{ unsigned int range[(max-min)/2]; } // note the curly braces!
else if (max<=ULONG_MAX)
{ unsigned long int range[(max-min)/2]; }
else if (max<=ULLONG_MAX)
{ unsigned long long int range[(max-min)/2]; }
so there's three range array declarations here, each in its own scope, inside the corresponding block. Each is created on entry to its enclosing block ({) and is destroyed on exit from it (}). In other words, it doesn't exist for the rest of your prime function anymore. Practically it means that if you declare your variable inside an if block, you can only use it inside that block (between the corresponding braces { and } ).
Q1: you can not declare a symbol (here: range) twice in the same scope. It is not exactly your problem but you are trying to do this: you declare range within the if scope and it is not visible outside.

Perfect square in fibonacci sequence?

Create a program to find out the first perfect square greater than 1 that occurs in the Fibonacci sequence and display it to the console.
I have no output when I enter an input.
#include <stdio.h>
#include <math.h>
int PerfectSquare(int n);
int Fibonacci(int n);
main()
{
int i;
int number=0;
int fibNumber=0;
int psNumber=0;
printf("Enter fibonacci number:");
scanf("%i",&number);
fibNumber = Fibonacci(number);
psNumber = PerfectSquare(fibNumber);
if(psNumber != 0){
printf("%i\n",psNumber);
}
}
int PerfectSquare(int n)
{
float root = sqrt(n);
if (n == ((int) root)*((int) root))
return root;
else
return 0;
}
int Fibonacci(int n){
if (n==0) return 0;
if (n==1) return 1;
return( Fibonacci(n-1)+Fibonacci(n-2) );
}
Luke is right. If your input is n, then the Fibonacci(n) returns the (n+1)th Fibonacci number.
Your program check whether (number +1)th is perfect square or not actually.
If you enter 12, then there is output. Because the 13th Fibonacci number is 144. And it is perfect square. PS: print fibNumber instead of psNumber.
printf("%i\n", fibNumber);
Right now you're only calculating one Fibonacci number and then testing whether it's a perfect square. To do this correctly you'll have to use a loop.
First suggestion is to get rid of the recursion to create fib numbers. You can use 2 variables and continually track the last 2 fib numbers. They get added something like:
fib1=0;fib2=1;
for(i=3;i<MAXTOCHECK;i++)
{
if(fib1<fib2)
fib1+=fib2;
else
fib2+=fib1;
}
What is nice about this method is that first you can change you seeds to anything you want. This is nice to find fib like sequences. For example Lucas numbers are seeded with 2 and 1. Second, you can put your check for square inline and not completely recalculate the sequence each time.
NOTE: As previously mentioned, your index may be off. There is some arbitrariness of indexing fib numbers from how it is initially seeded. This can seen if you reseed with 1 and 1. You get the same sequence shifted by 1 index. So be sure that you use a consistent definition for indexing the sequence.

Resources