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