Sunday, March 30, 2014

Update : 100 - The 3n + 1 problem

I was trying to optimize my 3n + 1 solution. My previous solution was through Brute Force method, which will calculate and max cycle length for every pairs of input. This solution was slow with the run time of 0.392s. The solution is in C++ as below:


#include<iostream>
using namespace std;

int main() {
 unsigned int lower, upper, temp, m, n;
 unsigned int i;
 int counter = 1;
 int max = 0;
 while (cin >> lower >> upper) {
  if (lower > upper) {
   upper = m;
   lower = n;
  } else {
   upper = n;
   lower = m;
  }
  if (upper < 1000000 && lower > 0) {
   for (i = lower; i <= upper; i++) {
    temp = i;
    while (i != 1) {
     if (i & 1) {
      i = (3 * i) + 1;
      i = i >> 1;
      counter += 2;
     } else {
      i = i >> 1;
      counter++;
     }
    }

    if (counter > max)
     max = counter;
    counter = 1;
    i = temp;
   }
   cout << m << " " << n << " " << max << endl;
   max = 1;
  }
 }
 return 0;
}

So i changed to another implementation, which is calculate the max cycle length and saved it into a array.
Initially i was trying to use an array of int.. but seems like its too big and when i try to run it with eclipse, the program stopped working. :-(
Googling around and found out there are people out there using array of short int for the same question and its works.
The solution is in C as below:

#include<stdio.h>

#define MAX 1000001
static unsigned short int cycle[MAX];

short int cycleLength(unsigned long int number) {
 if (number < MAX) {
  if (cycle[number]) {
   return cycle[number];
  }
  if (number & 1) {
   cycle[number] = 2 + cycleLength(((3 * number) + 1) >> 1);
  } else {
   cycle[number] = 1 + cycleLength(number >> 1);
  }
  return cycle[number];
 }
 if (number & 1) {
  return 2 + cycleLength(((3 * number) + 1) >> 1);
 } else {
  return 1 + cycleLength(number >> 1);
 }
}

int main() {

 unsigned int first, second;
 int counter;
 unsigned short int maxCycle = 0;
 unsigned short int temp;

 cycle[1] = 1;

 while (scanf("%u %u", &first, &second) != EOF) {
  maxCycle = 0;

  if (first < second) {

   for (counter = first; counter <= second; counter++) {
    temp = cycleLength(counter);
    if (temp > maxCycle) {
     maxCycle = temp;
    }
   }

  } else {

   for (counter = second; counter <= first; counter++) {
    temp = cycleLength(counter);
    if (temp > maxCycle) {
     maxCycle = temp;
    }
   }
  }

  printf("%u %u %d\n", first, second, maxCycle);
 }
 return 0;
}

The run time after the optimization was 0.032s . Please feel free to comment if you found that the code or algorithm can be further optimize.

No comments:

Post a Comment