Thursday, July 9, 2009

Small Recursive Wonder




Hello!!! So I am back after yet another loooooooong break from this blog. And this time I have a small but interesting problem whose solution I have just worked out...The problem is what I call "The random addition problem". Actually, this problem is a very simple one, one which most of us must have encountered in our day to day life...like giving changes for a given sum of money and many more. OK, so lifting the veil off, the problem is to find a subset of a set of numbers whose sum is equal to a given random number or to show failure if no such subset exists. So, the problem is precise, concise and clear :). Lets have an instance:

Test random number : 132,
Set of numbers: 24 3 17 8 96 43 6 55 89 998 254 678 123 90 546 46 32 5;

Now here the random number 132 can be made by adding the numbers of the subset (3,6,123) of this set.
Now think about this, "How did we come up with this set?". Naturally our brain goes on with doing this so fast that we don't recognize its process until we come up with a really long list or a really large number. But a little thinking can make it clear that we first try to grab the largest number (lets say 'K') of the set which is smaller than the given random number (lets say 'N'). Then we look for other number(s) in the set which can complement this number K to get the final number N. So essentially this is a recursive problem.

However, the other approach that looks straight-forward and brute-force but is quite often tricky, lengthy and may not come up with an answer is to simply keep on adding numbers starting from the beginning an d to go on until you find the number "N" or you end the list or you get a number > 'N'. Now this approach is not complete and as I said earlier may not come up with an answer even though the answer may exist. This is primarily due to the fact that this approach of adding numbers to a running sum can't accommodate for the fact that the required subset may comprise of numbers at different positions in the set.

So, now after all this discussion it quite clear that we should go with the recursive algo...(at least I'm going with it :) ).
So the first thing that we do is to eliminate all those numbers in the set (or array 'A[]' as we may call it) which are greater than 'N' because they are actually useless for us (You don't need an explanation for this... do you??? :P). Then we must sort the numbers in an ascending order. In my code I have done all this at the time of user input itself by using insertion sort. Next, we need to pop the numbers from this array (i.e. send the largest numbers one by one) into the recursive function. Once a number goes into the recursive function, we subtract it from 'N' and get a new number, say 'P'. This 'P' is the new number 'N' which we are now looking for in the list. If found our problem is solved, else we go on breaking this number 'P' by selecting the next highest number smaller than 'P' from the original array A[]. We can limit the search for the requisite number by a limiting pointer to this number. The recursion exits if this pointer reaches the first number in the array or the number to search 'P' becomes less than the least number in the array. The iteration then continues with the next highest number until we get a complete sequence or the whole array is finished.

Below is my simple C code for the problem. I think there are quite a few optimizations left in the code. This returns a sequence if it finds one or returns No if no answer is found...
Please post your comments if you find some optimizations or have some advice.

#include 
#include 
void print_array(int arr[], int len);
void copy_array(int arr1[], int arr2[], int len);
int check_for_sum(int num); //the main recursive function that does the job.
int found_in_b(int number);
int smaller_than_in_b(int numb);
int add_array(int arr[], int pntr);

//Global declarations
int num;
int num_needed;
int a[20];
int b[20];
int stack[20];
int stck_pntr = 0;
int a_len = 0;
int b_ptr = 0;

int add_array(int arr[], int pntr){
int sum = 0;
int i = 0;
while(i < pntr){   
sum += arr[i];  
i++;
}
return sum;
}

void print_array(int arr[], int len){
int i = 0;
while(i < len){
    
printf("%d, ",arr[i]); 
    
i++;
}
}

void copy_array(int arr1[], int arr2[], int len){
int i = 0;
while(i < len){
   
arr2[i] = arr1[i];
   
i++;
}
}

int found_in_b(int number){
int i = 0;
while(i < b_ptr){
  
if(b[i] == number)
      
return 1;
  
i++;
}   
return 0; 
}

int smaller_than_in_b(int numb){
int index = 0;
while((index < b_ptr) && (b[index] < numb)){
    
index++;
}
b_ptr = --index;
return b[index];
}

int check_for_sum(int number){
num_needed -= number;
if(num_needed < a[0] || (b_ptr<=1 && num_needed!=b[0]))
   
return 2;
else if(found_in_b(num_needed)==1 || num_needed==0)
   
return 1;
else{
   number = smaller_than_in_b(num_needed);
  
stack[stck_pntr++] = number;
   return check_for_sum(number);
}    
}

int main(int argc, char *argv[]){
printf("Enter the number to test: ");
scanf("%d",&num);
num_needed = num;
printf("Enter the numerical array (Enter -1 to exit):\n");
int last = 0;
do{
    int gen;
   
scanf("%d",&gen);
   
if(gen > 0){
          
if(gen <= num){
                 
while(gen < a[last-1] && last != 0){ 
                         
a[last] = a[last-1];
                           last--;
                   }
                  
a[last] = gen;
                   a_len++;
                   last = a_len;
          
}
    
}
    
else{

            break;
     
}
}while(a_len < 20);
int i = a_len - 1;
int val = 0;
while(i>=0){
       
copy_array(a, b, i);
        b_ptr = i; 
       
num_needed = num;
        stck_pntr = 0;
       
stack[stck_pntr] = a[i];
       
stck_pntr++;     
       
val = check_for_sum(a[i]);
       
i--;       
       
if(val==1)
          
break;
       
else
         
continue;
}

if(val(equal to)1){
      
printf("\nYes. You can use the series:\n");
       print_array(stack, stck_pntr);
      
stck_pntr = add_array(stack, stck_pntr);
       printf("%d.\n",num - stck_pntr);
}
else
    
printf("\nNo\n");
system("PAUSE"); 
return 0;
} 

Tuesday, March 24, 2009

Hey, now the Smith Numbers...

OK, So I am back, probably after sitting idle(just on the blogging front) for more than 6 months. I know that there is not even 1 chance in a million that someone would be waiting out there, he he he he. But that doesn't matter at all, I write just for personal satisfaction, as is the case with most of the bolggers, I guess... So, this time again I am going to write on another interesting series of numbers called the Smith Numbers. I just participated in a coding event and sadly this was the only coding question, I could manage through :(. Anyway, the numbers quite filled me with wonders and coding to generate them has been a joy for the evening. Smith numbers are those whose sum of digits is exactly same as the sum of the digits of their prime factors any prime factor appears more tan once, it counted as many number of times. Having said that, can you guess the smallest Smith number??? (Now don't say 1, as it is neither prime nor composite).

Well, its 4 = 2 x 2, the second smallest is 22 and so the list does on to an infinite limit (this was actually proved by a mathematician in 1987)and many maths freaks have found out interesting concepts such as Smith twins , i.e. consecutive Smith numbers (like 728, 729), Smith triplets and so on going up to the recently discovered Smith septets (A string of 7 consecutive smith numbers all of which are 12 digits long )

One interesting observation can be the fact that the beast number 666, is also a Smith Number.
OK so lets keep it brief and I should wrap up (Too much academic load at this time of the year). Below I have presented my code for testing whether a number is a Smith number or not (OK, I will admit that I am a lousy coder and no genius with all my hardly commented code, but that's it...). If u feel like going through more stuff on these numbers, make sure that you visit these links...

http://en.wikipedia.org/wiki/Smith_number

http://www.shyamsundergupta.com/smith.htm

And now the code :P

#include
#include
#include
#include

using namespace std;
typedef unsigned long int lint;
struct nod{
lint fact;
struct nod *n_ptr;
};
typedef struct nod Node;

Node Head;
Node *HEAD = &Head;

void prime_fact(lint);
void print_fact(lint);
void test_smith(lint);

int main(int argc, char *argv[])
{
lint num;
printf("Enter the number: \t");
cin >> num;
Head.fact = 0;
Head.n_ptr = NULL;
prime_fact(num);
print_fact(num);
test_smith(num);
free(HEAD);
cout << "\nMemory List Cleared!!!\n";
system("PAUSE");
return EXIT_SUCCESS;
}

void prime_fact(lint num)
{
lint i;
Node *head = &Head;
for(i=2;i {
if(num % i == 0)
{
num = num / i;
head->n_ptr = (Node *)malloc(sizeof(Node));
Head.fact = Head.fact + 1;
head = head->n_ptr;
head->fact = i;
head->n_ptr = NULL;
i = 2;
}
}
head->n_ptr = (Node *)malloc(sizeof(Node));
Head.fact = Head.fact + 1;
head = head->n_ptr;
head->fact = num;
head->n_ptr = NULL;
}

void print_fact(lint num)
{
int i;
Node *temp = &Head;
temp = temp->n_ptr;
cout << num << " = ";
for(i=0;i<(Head.fact);i++)
{
cout << temp->fact << " * ";
if(i==(Head.fact-1))
cout << "\b\b.";
temp = temp->n_ptr;
}
}

void test_smith(lint num)
{
int sum1; int sum2;
lint i = 0;
Node *tem = Head.n_ptr;
sum1 = sum2 =0;
do{
sum1 = sum1 + (num % 10);
num = num / 10;
}while(num>0);
//cout << "\n" << sum1 << "\t";
for(i=0;i {
do{
sum2 = sum2 + (tem->fact % 10);
tem->fact = tem->fact / 10;
}while((tem->fact)>0);
tem = tem->n_ptr;
}
//cout << sum2 << "\n";
if(sum1 == sum2)
cout << "\nCongo!!!We just discovered a Smith number.\n" ;
else
cout << "Not a Smith number dude!!!\n";
}

Wednesday, August 20, 2008

Enjoying my time with BITS (all puns intended)

So, after keeping this blog as a just an unfilled diary page for a large part of the semester, I am finally back to my blog.I really don't know what keeps on attracting me back to this page, but i guess it must be the sense of belonging to this whole space of mine. I had always planned to fill up my blog with posts atleast every week, but that couldn't materialise for the lack of ideas and initiative on my part as I am quite a lazy fellow. So, here i am today on 20th August , 08, sitting infront of my lappy and writing this post at completely ungodly hour of 4:30 am. I had long debated what to put up in my first post, with different ideas hitting me every time. But the most exciting development of the day(or shud I say yesterday????) has been my development of the code for the golomb series. Now, I realise that I may be taken as just another computer freak but I must say that to us, the programming beginners, the joy of surmounting even the tiniest of our problems is immense and it is in that pleasure that I am drunken today. Well, what happened is quite simple, I had developed some good codes at home during my vacations, but my great laptop which has of late developed a RAM problem, had to be formatted and i forgot to take any backup. That made me lose all my efforts of 2 and a half months.but no problems, our brain is perhaps a better hard disk than anything else. So I am currently in the process of recovering and modyfying all, what i say, my 'lost codes'. So I am precisely doing this thing at 10 pm (yesterday) when a friend from IIT Kanpur shows up. Now, this guy is a serious Java freak and even though I don't want to be drawn into an algorithm development discussion, yet i cannot resist doing so. So, now the talk veers to Golomb series, I doubted whether i had heard this word ever before. Even Googling doesn't render much help here.That may well be a part of the reason why i am writing this post.Someday, someone gonna dig this out and he (preferably she) may end up writing me a letter of thanx :). But before clouds of doubt clutter my thinking (i think i am being too grandiloquent, oops soorry!!) a mail with an attachment of the friend's assignment reaches me and i am on the go. the Golomb series turned out be rather simple and as the attachment says is pretty self explanatory. i must say that i have a special place for codes and sequences in my heart. I love finding patterns and structures in seemingly unconnected data and it has become quite a hobby with me. Now more about Golomb series. This is the only non-decreasing sequence of positive integers with the property that it contains exactly f(k) occurrences of k for each k. Sounds nerdy??? well blame it on IITs and IItians :D. The series is something like this:

n 1 2 3 4 5 6 7 8 9 10 11 12
f(n) 1 2 2 3 3 4 4 4 5 5 5 6

now the question was to develop a program to generate this sequence for a given 'n'taking time factors into consideration. As we can all see, there are some repetition sequences already there. but i envisaged a different set of patterns to generate the code for this series. First of all, we can see thatfor every n that is a perfect square, the f(n) is an odd numberwhich can be depicted as i + 2 if i = 1 for n = 1.
e.g. : when n=1, f(n)= 1.
when n=4, f(n)= 3. and so on...
Secondly, f(n) at a value of 'n' that is a perfect square repeats itself square root(n) number of times.

Lastly, between two 'n' values that are perfect squares there are larger square - (smaller square + 1) values of 'n' and f(n).

Now, thats all one needs to know to develop a very efficient solution to this problem. Here i present mine written in C++ language. though i agree that i have not added comments but  still you can make it out easily.Lastly i will agree that though this code is not the shortest one (there is infact a three line code that can use three for() loops instead) but certainly this is the one with the shortest time complexity :

 #include 
class abc{
 private :
  int per_sq(int u)
  {
int x;
for(x=1;x<=u;x++)
{
if((u-(x*x))==0)
return x;
}
return 0;
  }
  int near_sq(int v)
  {
 do{
v++;
 }while(per_sq(v)>0);
     return v;
  }
void golomb(int a)
{
int i, j, k, c;
i = 0;j = 1;
for(j=1;j<=a;)
{
c = per_sq(j);
if(c>0)
{
i++;
for(k=0;k
{
if(j<=a)
{
cout <<>
j++;
}
else
break;
}
}
else
{
 i++;
 for(k=0;k
 {
 if(j<=a)
 {
 cout << i ;
 j++;
 }
 else
break;
 }
}
}
}
 public :
  void get()
  {
 int n;
 cout << "Enter the value of n : ";
 cin >> n;
 golomb(n);
  }
};
void main()
{
 abc obj;
 obj.get();
}