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";
}