// Shawn O'Neil Dynamic Programming for optimal Matrix Multiplication,  Algorithms with Andy Poe Winter 04 

#include <iostream>
using namespace std;

int* getInput(int nummats);
void computeTable(int nummats, int* dimsarray);
void printOut(int **mults, int **divides, int nummats, int row, int col);

//Main method, calls IO and handes the case for only 1 matrix.
int main()
   {
   int nummats = 0;
   cout << "Please enter number of matrices:  ";
   cin >> nummats;
   if(nummats == 1)
      cout << "You need zero multiplications." << endl;
   else
      {
      int *dimsarray = getInput(nummats);
      computeTable(nummats, dimsarray);
      }
   }

//given a number of matrices, and an array of dimensions (size 1+nummats)
//computes the table of the least amount of multiplies from matrices a through b
//where this is stored in mults[a][b] (arrays start at 0, that is the number
//of mults required for the first through third arrays are stored in mults[0][2])
//and computes the appropropriate divide point for each multipilication in divides
void computeTable(int nummats, int* dimsarray)
   {
   int **mults = new int*[nummats];
   int **divides = new int*[nummats];
   for(int i = 0; i < nummats; i++)
      {
      mults[i] = new int[nummats];
      divides[i] = new int[nummats];
      }
   for(int i = 0; i < nummats; i++)
      for(int j = 0; j < nummats; j++)
         {mults[i][j] = -1; divides[i][j] = -1;}
   for(int i = 0; i < nummats; i++)
      mults[i][i] = 0;
   
   int y = 0;
   for(int i = 1; i < nummats; i++)
      {
      y = 0;
      for(int x = i; x < nummats; x++)
         {
         //here is where the order we want happens within the array, for x,y
         //so what is the least number of multiplications to multiply arrays y through x?
         //cout << x << "," << y << endl;
         //int othermults = mults[x-1][y];
         //if(mults[x][y+1] < othermults) othermults = mults[x][y+1];
         int togethermults = 0;
         if(x-y < 2)
            {
            togethermults = dimsarray[y]*dimsarray[x]*dimsarray[x+1];
            }
         else
            {
            for(int div = y; div < x; div++)    //divide after the divide number
               {
               int temp = dimsarray[y]*dimsarray[div+1]*dimsarray[x+1];
               temp += mults[div][y];
               temp += mults[x][div+1];
               if(temp < togethermults || togethermults == 0) 
                  {
                  togethermults = temp;
                  divides[x][y] = div;
                  }
               }
            }
         
         mults[x][y] = togethermults;
         //increment the y at the end
         y++;
         }
      }
   cout << "You need " << mults[nummats-1][0] << " multiplications." << endl;
   printOut(mults, divides, nummats, 0, nummats-1);
   cout << endl;
   }


//given a divides matrix and a row and column, prints out
//the parenthatized multiplation pattern for the optimal
//matrix multiplication of matrices row through column (again starting at 0)
// nummults = 5, 1,2,3,4,5,6 should be (((( 1 2 ) 3 ) 4 ) 5 )
// or in my format, (((( 0 1 ) 2 ) 3 ) 4 )
void printOut(int **mults, int **divides, int nummats, int row, int col)
   {
   //cout << "row is " << row << " col is " << col << endl;
   if(col-row == 0) cout << " " << row+1 << " ";
   else if(col-row == 1) cout << "( " << row+1 << "  " << row+2 << " )";//cout << "( "<< row << " " << row+1 << " )" << " ";
   else
      {
      int divide = divides[col][row];
      cout << "(";
      printOut(mults, divides, nummats, row, divide);

      printOut(mults, divides, nummats, divide+1, col);
      cout << ")";
      }
   }


//handes input, given a number of matrices, asks for the dimensions and returns them in an array
int* getInput(int nummats)
   {
   int *array;
   array = new int[nummats+1];
   for(int i = 0; i < nummats+1; i++)
      {
      if(i == 0) cout << "Please enter the number of rows in matrix 1:  ";
      else if(i == nummats) cout << "Please enter the number of columns in matrix " << nummats << ":  ";
      else cout << "Please enter the number of columns in matrix " << i << " and rows in matrix " << i+1 << ":  ";
      cin >> array[i];
      }
   return array;
   }