2

The gist of the program is to find the maximum sub array of a 1 dimensional array which has fluctuating stock prices using both a brute force method (Which is working!) and a divide and conquer method (which is not working). The intent of the program is to find the set of days (hence the lsub and rsub in the struct) and the maximum profit of those days.

Everywhere I have looked online such as this powerpoint shows that my code should work. I have also seen something similar to this, but in Java on StackOverflow, the implementation of that code also does not work. Here is the link to that Java program.

My code is as follows:

#include <stdio.h>
#include <iostream>
#include <climits>
#include <cstring>

struct funOut{
int lsub; //Left subscript
int rsub; //Right subscript
int maximum; //Contains the max value
 //This way, max has the absolute smallest value and only needs to be done once rather than at the beginning of the algorithm calls.
};

void load(int arr[], int n);
void brute(int arr[],  int n, funOut &out);
funOut dac(int arr[], int low, int high, funOut &out);
void findMax(int sumLval, int sumRval, funOut &sumMval, int low, int mid, int high, funOut &out);
funOut crossSum(int arr[], int low, int mid, int high);
void print(funOut out);

using namespace std;


int main(void)
{
   funOut out;

   string alg;
   cin >> alg;

   int n;
   cin >> n;

   int arr[n];

   // cout << n << endl;

   load(arr, n);
   if(alg[0] == 'b')
      brute(arr, n, out); //PARAMETERS NEEDED
   else if(alg[0] == 'd')
   {
      out.maximum = 0;
      out = dac(arr, 1, n-1, out);
   }

   else
   {
      cout << "\nERROR: No algorithm chosen, aborting program." << endl;
      return 0;
   }

   cout << "Before Print" << endl;
   print(out);
   return 0;
}

void load(int arr[], int n)
{
   cout << "Loading" << endl;
   for(int i=0; i<n; i++)
      cin >> arr[i];
}

void brute(int arr[], int n, funOut &out) //THIS WORKS!!!
{
   out.maximum = 0;
   int change;
   int temp = 0;
   for(int i=1; i<n-1; i++)
   {
      for(int j=i; j<n; j++)
      {
         change = arr[j] - arr[j-1];
         temp += change;
         if(temp > out.maximum){
            out.lsub = i;
            out.rsub = j;
            out.maximum = temp;
         }     
      }
      temp = 0;
   }
}

funOut dac(int arr[], int low, int high, funOut &out)
{
   cout << "DAC Start!" << endl;
   if(low == high)
   {
      out.lsub = out.rsub = low;
      out.maximum = arr[low];
      return out;
   }
   else
   {
      // cout << "DAC IF" << endl;
      int mid = (low + high)/2;

      funOut sumLval = dac(arr, low, mid, out);
      funOut sumRval = dac(arr, mid+1,high, out);
      funOut sumMval = crossSum(arr, low, mid, high);

      cout << "\nsumLval = " << sumLval.maximum << endl; 
      cout << "\nsumRval = " << sumRval.maximum << endl;
      cout << "\nsumMval = " << sumMval.maximum << endl;
      //FindMax
      if(sumLval.maximum >= sumRval.maximum && sumLval.maximum >= sumMval.maximum)
         return sumLval;         
      else if(sumRval.maximum >= sumLval.maximum && sumRval.maximum >= sumMval.maximum)
         return sumRval;
      else
         return sumMval;
   }
}



funOut crossSum(int arr[], int low, int mid, int high)
{
funOut sumMval;
int lsum = 0;
int rsum = 0;
int sum = 0;
int maxl, maxr;
//For loop finding lsum
for(int i=mid; i>=low; i--)
{
   cout << "DAC For I = " << i << endl;
   sum += arr[i];
   if(sum > lsum)
   {
      lsum = sum;
      maxl = i;
   }
}

sum = 0;

for(int j=mid+1; j<=high; j++)
{
   cout << "DAC For J = "<< j << endl;
   sum += arr[j];
   if(sum > rsum)
   {
      rsum = sum;
      maxr = j;
   }
}

sumMval.lsub = maxl;
sumMval.rsub = maxr;
sumMval.maximum = lsum + rsum;

return sumMval;
}

void print(funOut out)
{
   cout << "The max value is: ";
   cout << out.maximum << endl;
   cout << "The left subscript is: ";
   cout << out.lsub << endl;
   cout << "The right subscript is: ";
   cout << out.rsub << endl;
}

Sample data set: (They are supposed to be on seperate lines but it isn't letting me do so.)

d
17
100
113
110
85
105
102
86
63
81
101
94
106
101
79
94
90
97

The intended output is:

The max value is: 43

The left subscript is: 8

The right subscript is: 11

Community
  • 1
  • 1
messem10
  • 33
  • 4
  • Have you tried stepping through with a debugger? – Tony The Lion Sep 16 '12 at 22:48
  • How do you know it's not working? Can you give us an example? Could you put it into `main` so that we don't have to guess? – Beta Sep 16 '12 at 23:00
  • I have compiled it through g++ and it goes through, but the results when doing the divide-and-conquer algorithm are incorrect. – messem10 Sep 16 '12 at 23:09
  • @pyCthon I have debugged it using cout throughout the program, yet I cannot find the source of where it goes haywire. I am at the point now where I am "brain dead" meaning that I have been looking at this so long it is causing a headache. – messem10 Sep 16 '12 at 23:44

1 Answers1

0

Conceptually, your brute-force method is doing a whole lot of redundant work.

When you add up all the point-to-point differences in an array, all you get is the difference between the ends:

int diff = (x[1] - x[0]) + (x[2] - x[1]) + (x[3] - x[2]) + (x[4] - x[3]);

The above is the same as this (because all the other values cancel out):

int diff = x[4] - x[0];

So all your brute-force algorithm seems to be doing is searching for the i and j with the greatest difference constrained by i < j. This is equivalent to finding the min and max of the array, where min appears before the max.

Looks to me like a problem for dynamic programming. I don't see how divide-and-conquer is useful for this problem.

[edit]

So, I think the problem is crossSum. It's doing something utterly different from brute. Surely you just want to find the index of the minimum value in the left (minl) and the index of the maximum value in right (maxr). The 'maximum' in that output struct is simply arr[maxr] - arr[minl].

Funny thing is that the divide-and-conquer approach is still needlessly inefficient for this problem. Consider this:

struct funOut f;
f.lsub = 0;
f.rsub = 0;
f.maximum = 0;

int minval = arr[0];
int minidx = 0;

for( int i = 1; i < n; i++ ) {
    if( arr[i] < minval ) {
        minval = arr[i];
        minidx = i;
        continue;
    }

    int delta = arr[i] - minval;
    if( delta > f.maximum ) {
        f.lsub = minidx;
        f.rsub = i;
        f.maximum = delta;
    }
}
paddy
  • 60,864
  • 6
  • 61
  • 103
  • I originally had my brute force like you stated, but I could not get it to work, so I went for the one that worked. The divide and conquer is not something I added in there for fun, but it is a requirement for the assignment. I have been working on this program for about 15+ hours. Six of those hours have been spent on the Divide and Conquer portions. (The dac() and crossSum() functions) – messem10 Sep 16 '12 at 23:43
  • I cannot get the 'intended output' from your edited question by following the `brute` function. Have you left something out? To me, the values '17' and '113' in your dataset show the maximum profit. If you agree with what I have said about how your brute-force function is actually working, I can offer you a simple algorithm to compute the same thing in linear time. If you do not agree, then the code you have shown does not do what you think it does. – paddy Sep 16 '12 at 23:45
  • Oh, my mistake!! 17 is the array size isn't it =) – paddy Sep 16 '12 at 23:51
  • So, I think the problem is `crossSum`. It's doing something utterly different from `brute`. Surely you just want to find the index of the minimum value in the left and the index of the maximum value in right. The 'maximum' is simply `arr[maxr] - arr[minl]`. Funny thing is that this particular divide-and-conquer approach is still really inefficient. – paddy Sep 17 '12 at 00:02
  • The only issue with this solution for crossSum is that there are times where it isn't as simple as going from the minimum on the left to the largest on the right, it is also tallying up the changes from the values between them. I realize that it is just easier to brute force this, but I was tasked with finding a divide and conquer solution too. Now that I look at the brute force code that you shared, it is much simpler than I had originally imagined. – messem10 Sep 17 '12 at 00:44
  • Why is it not that simple? That is exactly what your `brute` function does, and you said it produces the correct output. By the way, the code I supplied you is not brute-force. It is dynamic programming, and works by understanding that if a better minimum comes along then no previously-occurring minimum value will lead to an optimal solution. In contrast, a brute-force algorithm considers every possibility, including those that are guaranteed to produce worse answers than it has already calculated. My solution is O(N); divide-and-conquer is O(NlogN); brute-force is O(N^2) – paddy Sep 17 '12 at 01:06
  • We are getting introduced to dynamic programming now yet with your explanation of the code, it makes perfect sense! Thank you so much for your help. I feel dumb for not realizing that if a better minimum comes along, then that is the best one! – messem10 Sep 17 '12 at 01:16