Listing 3: Partial listing of TimeShareSolver.cpp

STDMETHODIMP CTimeShareSolver::Solve()
{
   //
   // Read the database.
   ReadOwnerInfo();
   //
   // Initialization.
   Initialize();
   //
   // Main loop.
   for (m_iterCnt =0;m_iterCnt<MAX_ITERATIONS;m_iterCnt++)
   {
      AssignOwners();
      SwapOwners();
      EvaluateCost();
      UnassignOwners();
   }
   //
   // Update the database.
   WriteBestSolution();
   return S_OK;
}

CTimeShareSolver::Initialize()
{
   //
   // Initialize all owners to unassigned.
   m_trialCostTotal = 0;
   for (int i = 0;i<m_ownerCnt;i++)
   {
      int cost = m_owner[i].CalcCost(UNASSIGNED);
      m_trial[i] = UNASSIGNED;
      m_curr[i] = UNASSIGNED;
      m_best[i] = UNASSIGNED;
      m_trialCost[i] = cost;
      m_trialCostTotal += cost;
   }
   //
   //  Initially the trial = curr = best soln.
   m_currCostTotal = m_trialCostTotal;
   m_bestCostTotal = m_trialCostTotal;
   //
   //  Initialize capacity data.
   for (int p =0;p < MAX_PERIODS;p++)
   {
      m_unitsOccup [p] = 0;
      m_totalOccup [p] = 0;
   }
   m_iterCnt = 0;
   srand(1); // Init random number generator.
}

CTimeShareSolver::AssignOwners()
{
   vector <bool> tryToAssign ( m_ownerCnt, false);
   int tryToAssignCnt = 0;
   for (int i=0;i<m_ownerCnt;i++)
   {
      if (m_trial[i] == UNASSIGNED)
      {
         tryToAssign[i] = true;
         tryToAssignCnt++;
      }
   }
   while (tryToAssignCnt > 0)
   {
      // Select one of the unassigned owners
      // with most occupants.
      RandomMax hiOcc;
      hiOcc.Initialize( 4);
      for (i=0;i<m_ownerCnt;i++)
      {
         if (tryToAssign[i])
            hiOcc.Compare(i, m_owner[i].m_occupCnt);
      }
      i = hiOcc.RandomSelectIndex();
      //
      //  Try to get one of the owner's first 3 choices.
      int choice = 0;
      while ((choice < 3)&&(m_trial[i] == UNASSIGNED))
      {
         int period = m_owner[i].m_choice[choice];
         if (m_unitsOccup[period] < MAX_UNITS)
         {
            int trialOcc = m_totalOccup[period];
            trialOcc +=  m_owner[i].m_occupCnt;
            if (trialOcc <= MAX_OCCUPANTS)
               Assign( i, period);
         }
         choice++;
      }
      //
      //  If owner is still unassigned. Try assigning him to
      //  the open period with the most occupants.
      if (m_trial[i] == UNASSIGNED)
      {
         int bestPeriod = -1;
         int maxOcc = -1;
         for (int period=0;period<MAX_PERIODS;period++)
         {
            if (m_unitsOccup[period] < MAX_UNITS)
            {
               int trialOcc = m_totalOccup[period];
               trialOcc += m_owner[i].m_occupCnt;
               if ((trialOcc <= MAX_OCCUPANTS)
                 &&(trialOcc > maxOcc))
               {
                  bestPeriod = period;
                  maxOcc = trialOcc;
               }
            }
         }
         if (bestPeriod != -1)
            Assign( i, bestPeriod);
      }
      tryToAssign[i] = false;
      tryToAssignCnt--;
   }
}

CTimeShareSolver::SwapOwners()
{
   vector <bool> tryToSwap ( m_ownerCnt, false);
   int tryToSwapCnt = 0;
   for (int i=0;i<m_ownerCnt;i++)
   {
      if (m_trialCost[i] > 0)
      {
         tryToSwap[i] = true;
         tryToSwapCnt++;
      }
   }
   while (tryToSwapCnt > 0)
   {
      RandomMax hiCost;
      hiCost.Initialize( 3);
      for (i=0;i<m_ownerCnt;i++)
      {
         // Select one of the unassigned owners
         // with highest cost.
         if (tryToSwap[i])
            hiCost.Compare(i, m_trialCost[i]);
      }
      i = hiCost.RandomSelectIndex();
      //
      //  We make swaps by unassigning first.
      //  Then reassign to someone else's spot.
      //  or back to the original spot.
      if (m_trial[i] != UNASSIGNED)
         Unassign( i);
      Swap(i);
      tryToSwap[i] = false;
      tryToSwapCnt--;
   }
}

CTimeShareSolver::UnassignOwners()
{
   int assignCnt  = 0;
   for (int i = 0;i<m_ownerCnt;i++)
   {
      if (m_trial[i] != UNASSIGNED)
         assignCnt++;
   }
   //
   // Unassign 15% of highest cost assignments.
   int unassignTarget = 15*assignCnt/100;
   while (unassignTarget > 0)
   {
      // Select one of the unassigned owners
      // with highest cost.
      RandomMax hiCost;
      hiCost.Initialize( 4);
      for (i=0;i<m_ownerCnt;i++)
      {
         if (m_trial[i] != UNASSIGNED)
            hiCost.Compare(i, m_trialCost[i]);
      }
      i = hiCost.RandomSelectIndex();
      if (m_trial[i] != UNASSIGNED)
      {
         Unassign(i);
         unassignTarget--;
      }
   }

   //
   // Remove an additional 5% at random.
   unassignTarget = 5*assignCnt/100;
   while (unassignTarget > 0)
   {
      int i=randomNum(m_ownerCnt);
      if (m_trial[i] != UNASSIGNED)
      {
         Unassign(i);
         unassignTarget--;
      }
   }
}


CTimeShareSolver::EvaluateCost()
{
   //
   //  First adjust the simulated annealing temperature;
   if (m_iterCnt== 0)
      m_saTemp = 0.05*m_trialCostTotal + 1.0;// initialize
   else if ((m_iterCnt % (MAX_ITERATIONS/20)) == 0)
      m_saTemp = 0.90*m_saTemp; // make 20 reductions of 10%
   //
   // First check for new best solution.
   if (m_trialCostTotal < m_bestCostTotal)
   {
      // A new best solution was found.
      // Copy trial solution to best solution.
      for (int i =0;i < m_ownerCnt;i++)
         m_best[i] = m_trial[i];
      m_bestCostTotal = m_trialCostTotal;
      //
      //  Copy trial solution to current solution.
      for (i =0;i < m_ownerCnt;i++)
         m_curr[i] = m_trial[i];
      m_currCostTotal = m_trialCostTotal;

      char buff[400];
      sprintf( buff, "Iteration %d NEW BEST SOLUTION = %d\n",
         m_iterCnt, m_bestCostTotal);
      OutputDebugString(buff);

   }
   else
   {
      double delta = m_currCostTotal - m_trialCostTotal;
      double anneal = exp(delta/m_saTemp);
      double randVal = randomNum(1000)/1000.0;
      if (randVal < anneal)
      {
         //
         //  Keep the trial solution.
         for (int i =0;i < m_ownerCnt;i++)
            m_curr[i] = m_trial[i];
         m_currCostTotal = m_trialCostTotal;
      }
      else
      {
         //
         // Discard trial soln. Go back to curr soln.
         for (int p =0;p < MAX_PERIODS;p++)
         {
            m_unitsOccup [p] = 0;
            m_totalOccup [p] = 0;
         }
         for (int i =0;i < m_ownerCnt;i++)
         {
            int p = m_curr[i];
            m_trial[i] = p;
            m_trialCost[i] = m_owner[i].CalcCost(p);
            if (p != UNASSIGNED)
            {
               m_unitsOccup[p]++;
               m_totalOccup[p] += m_owner[i].m_occupCnt;
            }
         }
         m_trialCostTotal = m_currCostTotal;
      }
   }
}
— End of Listing —