爱因斯坦的问题,以下是问题提示和C++的解决方案(老外写的) 供大家学习ING
下面的问题相信很多人都听过:
1 有五栋五种颜色的房子
2 每一位房子的主人国籍都不同
3 这五个人每人只喝一种饮料,只抽一种牌子的香烟,只养一种宠物
4 没有人有相同的宠物,抽相同牌子的香烟,喝相同的饮料
提示:
1、 英国人住在红房子里
2 、瑞典人养了一条狗
3 、丹麦人喝茶
4 、绿房子在白房子左边
5 、绿房子主人喝咖啡
6 、抽PALL MALL烟的人养了一只鸟
7 、黄房子主人抽DUNHILL烟
8 、住在中间那间房子的人喝牛奶
9 、挪威人住第一间房子
10 、抽混合烟的人住在养鱼人的旁边
11 、养马人住在DUNHILL烟的人旁边
12 、抽BLUE MASTER烟的人喝啤酒
13、 德国人抽PRINCE烟
14 、挪威人住在蓝房子旁边
15 、抽混合烟的人的邻居喝矿泉水
问题是:谁养鱼?
#include "Einstein.h"
#include <windows.h>
#define COUNT_SEARCHES 1
#define FILL_IN 1
CHouse CHint::house[COUNT_HOUSES];
CHouse* CHint::propowner[COUNT_CATEGORIES*COUNT_EXTENDED_CatID];
int CSolver::count_nodes = 0;
int CHint::count_solutions = 0;
// Array of pointers to CHint objects, i.e. a list of hints.
//
// I just keep the hint list in Einstein's order.
// Should you not want to be fooled by his
// tricky order, you could move the smiplest
// hints, hint 8 and hint 9 for example, to the
// top of the list so that the program searches
// fewer nodes.
//
CHint* CSolver::hint[] =
{
// 1. the Brit lives in the red house
new CSingleHouseHint(BRIT, RED),
// 2. the Swede keeps dogs as pets
new CSingleHouseHint(SWEDE, DOG),
// 3. the Dane drinks tea
new CSingleHouseHint(DANE, TEA),
// 4. the green house is on the immediate left of the white house
new COrderedNeighborsHint(GREEN, WHITE),
// 5. the green house's owner drinks coffee
new CSingleHouseHint(GREEN, COFFEE),
// 6. the person who smokes Pall Mall rears birds
new CSingleHouseHint(PALLMALL, BIRD),
// 7. the owner of the yellow house smokes Dunhill
new CSingleHouseHint(YELLOW, DUNHILL),
// 8. the man living in the center house drinks milk
new CKnownHouseHint(HOUSE2, MILK),
// 9. the Norwegian lives in the first house
new CKnownHouseHint(HOUSE0, NORWEGIAN),
// 10. the man who smokes blends lives next to the one who keeps cats
new CNeighborsHint(BLENDS, CAT),
// 11. the man who keeps horses lives next to the man who smokes Dunhill
new CNeighborsHint(HORSE, DUNHILL),
// 12. the owner who smokes BlueMaster drinks beer
new CSingleHouseHint(BLUEMASTER, BEER),
// 13. the German smokes Prince
new CSingleHouseHint(GERMAN, PRINCE),
// 14. the Norwegian lives next to the blue house
new CNeighborsHint(NORWEGIAN, BLUE),
// 15. the man who smokes blends has a neighbor who drinks water
new CNeighborsHint(BLENDS, WATER)
};
int __cdecl main(int argc, char* argv[])
{
CSolver::DoTheWork();
printf("Press any key to end the program ....");
getch();
return 0;
}
void CSolver::DoTheWork()
{
__int64 start, finish, freq;
PrintEinsteinRiddleDescription();
QueryPerformanceFrequency((LARGE_INTEGER*) &freq);
QueryPerformanceCounter((LARGE_INTEGER*) &start);
for (int i = 0; i < COUNT_SEARCHES; i++)
Search(&hint[0]); // start the engine with the first hint
QueryPerformanceCounter((LARGE_INTEGER*) &finish);
printf("/nProgram finished the exhaustive search of %d nodes in %.5f seconds and/n",
GetNodeCount(), (double) (finish - start) / (double) freq);
printf("found %d solution(s)./n/n", CHint::GetSolutionCount()/COUNT_SEARCHES);
}
void CSolver::PrintEinsteinRiddleDescription()
{
// this is the problem decription
static const char sRiddle[][75] =
{
"Einstein wrote a riddle last century. He said that 98% of the world could",
"not solve it. ",
"",
"Einstein's riddle",
"There are 5 houses in five different colors in a row.",
"In each house lives a person with a different nationality. ",
"The five owners drink a certain type of beverage, smoke a certain brand of",
"cigar and keep a certain pet.",
"No owners have the same pet, smoke the same brand of cigar or drink the",
"same beverage.",
"",
"The question is: Who owns the fish?",
"",
"Einstein's hints:",
" 1. The Brit lives in the red house",
" 2. The Swede keeps dogs as pets",
" 3. The Dane drinks tea",
" 4. The green house is on the immediate left of the white house",
" 5. The green house's owner drinks coffee",
" 6. The person who smokes Pall Mall rears birds",
" 7. The owner of the yellow house smokes Dunhill",
" 8. The man living in the center house drinks milk",
" 9. The Norwegian lives in the first house",
"10. The man who smokes blends lives next to the one who keeps cats",
"11. The man who keeps horses lives next to the one who smokes Dunhill",
"12. The owner who smokes BlueMaster drinks beer",
"13. The German smokes Prince",
"14. The Norwegian lives next to the blue house",
"15. The man who smokes blends has a neighbor who drinks water"
};
for (int i = 0; i < sizeof(sRiddle)/75; i++)
puts(sRiddle[i]);
puts("/n/nMachine's solution(s):/n");
}
void CSolver::Search(CHint** ppCHint)
{
CHint* pCHint = *ppCHint; // pointer to current hint
IncNodeCount(); // increament node count
pCHint->ResetSeekPosition(); // reset to start position
while (pCHint->AssignPropToNextEligibles()) // seek and assign each eligibles
{ // with properties.
if (ppCHint != &hint[sizeof(hint)/sizeof(CHint*) - 1]) // is not the last
Search(ppCHint + 1); // search with next hint
else // all hints have been met
CHint::PrintOut(); // a solution has been found
pCHint->RemovePropFromPrevEligibles(); // undo the assign operations
}
}
// remove property from the new owner if it exists
//
inline void CHint::RemoveProperty()
{
if (m_pNewOwner0)
{
m_pNewOwner0->ClearProperty(m_pid0);
RegisterOwnership(m_pid0, NULL); // nobody owns m_pid0 now
}
}
__forceinline int CHint::AssignPropertySetNextPos(CHouse* p0, CHouse* pNext)
{
m_pNext = pNext; // set next start for next seek
if (p0 == NULL) // m_pid0 has a owner alread
m_pNewOwner0 = NULL; // set no new owner flag
else
{
m_pNewOwner0 = p0; // keep the new owner for later recall
p0->SetProperty(m_pid0);
RegisterOwnership(m_pid0, p0); // p0 now has the title for m_pid0
}
return -1;
}
void CMultiPropertiesHint::RemovePropFromPrevEligibles()
{
RemoveProperty();
if (m_pNewOwner1)
{
m_pNewOwner1->ClearProperty(m_pid1);
RegisterOwnership(m_pid1, NULL); // nobody owns m_pid1 now
}
}
__forceinline int CMultiPropertiesHint::AssignPropertiesSetNextPos(CHouse* p0,
CHouse* p1,
CHouse* pNext)
{
AssignPropertySetNextPos(p0, pNext);
if (p1 == NULL) // m_pid1 has a owner alread
m_pNewOwner1 = NULL; // set no new owner flag
else
{
m_pNewOwner1 = p1; // keep the new owner for later recall
p1->SetProperty(m_pid1);
RegisterOwnership(m_pid1, p1); // p1 now has the title for m_pid1
}
return -1;
}
int CKnownHouseHint::AssignPropToNextEligibles()
{
if (m_pNext == NULL) // NULL is the stop sign
return 0;
CHouse* pOwner = GetPropertyOwner(m_pid0);
if (pOwner) // property m_pid0 has a owner already
{
if (pOwner == m_pKnownHouse) // is it the required owner?
return AssignPropertySetNextPos(NULL, NULL);
return 0;
}
else if (m_pKnownHouse->IsEmpty(m_pid0))
return AssignPropertySetNextPos(m_pKnownHouse, NULL);
else
return 0;
}
int COrderedNeighborsHint::AssignPropToNextEligibles()
{
if (m_pNext >= &house[HOUSE4]) // &house[HOUSE4] acts as a stop sign:)
return 0;
CHouse* pOwner0 = GetPropertyOwner(m_pid0);
CHouse* pOwner1 = GetPropertyOwner(m_pid1);
if (pOwner0 && pOwner1) // both m_pid0 and m_pid1 have owners already
{
if (pOwner1 == pOwner0 + 1) // pOwner0 is on the immmeadiate left of pOwner1
return AssignPropertiesSetNextPos(NULL, NULL, &house[HOUSE4]);
return 0;
}
else if (pOwner0) // pOwner1 == NULL; nobody owns m_pid1
{
if (pOwner0 < &house[HOUSE4] && (pOwner0 + 1)->IsEmpty(m_pid1))
return AssignPropertiesSetNextPos(NULL, pOwner0 + 1, &house[HOUSE4]);
return 0;
}
else if (pOwner1) // pOwner0 == NULL; nobody owns m_pid0
{
if (pOwner1 > &house[HOUSE0] && (pOwner1 - 1)->IsEmpty(m_pid0))
return AssignPropertiesSetNextPos(pOwner1 - 1, NULL, &house[HOUSE4]);
return 0;
}
else // pOwner0 == NULL && pOwner1 == NULL; nobody owns m_pid0 or m_pid1
{
CHouse* p = m_pNext;
while (p < &house[HOUSE4])
{
if (p->IsEmpty(m_pid0) && (p + 1)->IsEmpty(m_pid1))
return AssignPropertiesSetNextPos(p, p + 1, p + 1);
p++;
}
return 0;
}
}
int CSingleHouseHint::AssignPropToNextEligibles()
{
if (m_pNext >= &house[COUNT_HOUSES]) // &house[COUNT_HOUSES] acts as stop sign
return 0;
CHouse* pOwner0 = GetPropertyOwner(m_pid0);
CHouse* pOwner1 = GetPropertyOwner(m_pid1);
if (pOwner0 && pOwner1)
{
if (pOwner0 == pOwner1)
return AssignPropertiesSetNextPos(NULL, NULL, &house[COUNT_HOUSES]);
return 0;
}
else if (pOwner0) // pOwner1 == NULL; nobody owns m_pid1
{
if (pOwner0->IsEmpty(m_pid1))
return AssignPropertiesSetNextPos(NULL, pOwner0, &house[COUNT_HOUSES]);
return 0; // failed
}
else if (pOwner1) // pOwner0 == NULL; nobody owns m_pid0
{
if (pOwner1->IsEmpty(m_pid0))
return AssignPropertiesSetNextPos(pOwner1, NULL, &house[COUNT_HOUSES]);
return 0;
}
else // pOwner0 == NULL && pOwner1 == NULL; nobody owns m_pid0 or m_pid1
{
CHouse* p = m_pNext;
while (p < &house[COUNT_HOUSES])
{
if (p->IsEmpty(m_pid0) && p->IsEmpty(m_pid1))
return AssignPropertiesSetNextPos(p, p, p + 1);
p++;
}
return 0;
}
}
int CNeighborsHint::AssignPropToNextEligibles()
{
if (m_pNext >= &house[HOUSE4]) // &house[HOUSE4] acts as stop sign
return 0;
CHouse* pOwner0 = GetPropertyOwner(m_pid0);
CHouse* pOwner1 = GetPropertyOwner(m_pid1);
if (pOwner0 && pOwner1)
{
if (pOwner0 - pOwner1 == 1 || pOwner0 - pOwner1 == -1)
return AssignPropertiesSetNextPos(NULL, NULL, &house[HOUSE4]);
return 0;
}
else if (pOwner0) // pOwner1 == NULL; nobody owns m_pid1
{
if (!m_NextReverse && pOwner0 < &house[HOUSE4] && (pOwner0 + 1)->IsEmpty(m_pid1))
{
m_NextReverse = -1;
return AssignPropertiesSetNextPos(NULL, pOwner0 + 1, pOwner0);
}
if (pOwner0 > &house[HOUSE0] && (pOwner0 - 1)->IsEmpty(m_pid1))
return AssignPropertiesSetNextPos(NULL, pOwner0 - 1, &house[HOUSE4]);
return 0;
}
else if (pOwner1) // pOwner0 == NULL; nobody owns m_pid0
{
if (!m_NextReverse && pOwner1 < &house[HOUSE4] && (pOwner1 + 1)->IsEmpty(m_pid0))
{
m_NextReverse = -1;
return AssignPropertiesSetNextPos(pOwner1 + 1, NULL, pOwner1);
}
if (pOwner1 > &house[HOUSE0] && (pOwner1 - 1)->IsEmpty(m_pid0))
return AssignPropertiesSetNextPos(pOwner1 - 1, NULL, &house[HOUSE4]);
return 0;
}
else // pOwner0 == NULL && pOwner1 == NULL
{
CHouse* p = m_pNext;
while (p < &house[HOUSE4])
{
if (!m_NextReverse && p->IsEmpty(m_pid0) && (p + 1)->IsEmpty(m_pid1))
{
m_NextReverse = -1;
return AssignPropertiesSetNextPos(p, p + 1, p);
}
if (p->IsEmpty(m_pid1) && (p + 1)->IsEmpty(m_pid0))
{
m_NextReverse = 0;
return AssignPropertiesSetNextPos(p + 1, p, p + 2);
}
p += 2;
}
return 0;
}
}
// This function is to verify current solution and is to be called whenever a
// solution is found.
//
// return:
// NULL: failed for search error(s).
// nonzero: pointer to the owner of the fish
//
CHouse* CHint::VerifyCurrentSolution()
{
CHouse* pFishOwner = NULL;
for (int i = 0; i < COUNT_HOUSES; i++)
{
if (house[i].IsEmpty(COLOR) || house[i].IsEmpty(NATIONALITY) ||
house[i].IsEmpty(BAVERAGE) || house[i].IsEmpty(CIGAR)
)
return NULL;
if (house[i].IsEmpty(PET))
if (pFishOwner)
return NULL;
else
pFishOwner = &house[i];
}
return pFishOwner;
}
// This interface function verifies and prints out the current solution
//
void CHint::PrintOut()
{
IncSolutionCount(); // the solution is valid
#if FILL_IN > 0
CHouse* pFishOwner = VerifyCurrentSolution();
if (pFishOwner == NULL)
{
puts("found a search error./n");
return;
}
// we have also to fill in the fish before sending a solution solution to
// the screen because Einstein did not mention it in his hints.
//
pFishOwner->SetProperty(FISH);
#endif
printout();
#if FILL_IN > 0
pFishOwner->ClearProperty(FISH); // restore the world for further search
#endif
}
// Print a solution on console screen
// Some of the drawing code in this function was borrowed from Manfred Becker's.
//
void CHint::printout()
{
static const char sColor[][7 + 1] =
{
" blue ", " green", " red ", " white", " yellow"
};
static const char sNationality[][9 + 1] =
{
" Brit ", " Dane ", " German ", "Norwegian", " Swede "
};
static const char sBaverage[][7 + 1] =
{
" Beer ", " Coffee", " Milk ", " Tea ", " Water"
};
static const char sCigar[][9 + 1] =
{
" Blends ", "BlueMastr", " Dunhill ", "Pall Mall", " Prince " };
static const char sPet[][7 + 1] =
{
" Bird ", " Cat ", " Dog ", " Fish ", " Horse"
};
static const char sWild7[] = " * ";
static const char sWild9[] = " * ";
static char sln[][79] =
{
" / // / // / // / // / //",
" / // / // / // / // / //",
" / 1 // / 2 // / 3 // / 4 // / 5 //",
" / // / // / // / // / //",
" / // / // / // / // / // ",
"/___________// /___________// /___________// /___________// /___________//",
"| | | | | | | | | |",
"| | | | | | | | | |",
"| | | | | | | | | |",
"| | | | | | | | | |",
"| | | | | | | | | |",
"|___________| |___________| |___________| |___________| |___________|"
};
// Print houses...
int i;
for (i = 0; i < COUNT_HOUSES; i++)
{
memcpy(&sln[4][2 + 15*i], house[i].IsEmpty(COLOR) ? sWild7 : sColor[house[i].GetPropIndex(COLOR)], 7);
memcpy(&sln[7][2 + 15*i], house[i].IsEmpty(NATIONALITY) ? sWild9 : sNationality[house[i].GetPropIndex(NATIONALITY)], 9);
memcpy(&sln[8][2 + 15*i], house[i].IsEmpty(BAVERAGE) ? sWild7 : sBaverage[house[i].GetPropIndex(BAVERAGE)], 7);
memcpy(&sln[9][2 + 15*i], house[i].IsEmpty(CIGAR) ? sWild9 : sCigar[house[i].GetPropIndex(CIGAR)], 9);
memcpy(&sln[10][2 + 15*i], house[i].IsEmpty(PET) ? sWild7 : sPet[house[i].GetPropIndex(PET)], 7);
}
for (i = 0; i < sizeof(sln)/79; i++)
puts(sln[i]);
puts("/n");
}
以下是头文件内容:
#include <iostream>
#include <conio.h>
#include <time.h>
enum Problem_Constants
{
COUNT_HOUSES = 5,
COUNT_CATEGORIES = 5,
// COUNT_HINTS = 15,
BITS_CatID = 3,
COUNT_EXTENDED_CatID = 1 << BITS_CatID // COUNT_EXTENDED_CatID = 8
};
// Property Category ID
enum CatID
{
COLOR,
NATIONALITY,
BAVERAGE,
CIGAR,
PET
};
// Property Identifications
enum PropID
{
BLUE = (0 << BITS_CatID) | COLOR,
GREEN = (1 << BITS_CatID) | COLOR,
RED = (2 << BITS_CatID) | COLOR,
WHITE = (3 << BITS_CatID) | COLOR,
YELLOW = (4 << BITS_CatID) | COLOR,
BRIT = (0 << BITS_CatID) | NATIONALITY,
DANE = (1 << BITS_CatID) | NATIONALITY,
GERMAN = (2 << BITS_CatID) | NATIONALITY,
NORWEGIAN = (3 << BITS_CatID) | NATIONALITY,
SWEDE = (4 << BITS_CatID) | NATIONALITY,
BEER = (0 << BITS_CatID) | BAVERAGE,
COFFEE = (1 << BITS_CatID) | BAVERAGE,
MILK = (2 << BITS_CatID) | BAVERAGE,
TEA = (3 << BITS_CatID) | BAVERAGE,
WATER = (4 << BITS_CatID) | BAVERAGE,
BLENDS = (0 << BITS_CatID) | CIGAR,
BLUEMASTER = (1 << BITS_CatID) | CIGAR,
DUNHILL = (2 << BITS_CatID) | CIGAR,
PALLMALL = (3 << BITS_CatID) | CIGAR,
PRINCE = (4 << BITS_CatID) | CIGAR,
BIRD = (0 << BITS_CatID) | PET,
CAT = (1 << BITS_CatID) | PET,
DOG = (2 << BITS_CatID) | PET,
FISH = (3 << BITS_CatID) | PET,
HORSE = (4 << BITS_CatID) | PET
};
enum HouseID
{
HOUSE0, HOUSE1, HOUSE2, HOUSE3, HOUSE4
};
class CHouse
{
private:
enum
{
// EMPTY is a flag to indicate a null property of any category.
// Its value must not be equal to any real property (any element of PropID).
EMPTY = (0 << BITS_CatID) | PET + 1
};
PropID m_property[COUNT_CATEGORIES];
// constructor
public:
CHouse()
{
for (int i = 0; i < COUNT_CATEGORIES; i++)
m_property[i] = (PropID) EMPTY;
}
// operations
public:
int IsEmpty(CatID cid) { return m_property[cid] == EMPTY; }
int IsEmpty(PropID pid) { return IsEmpty(GetCatID(pid)); }
int GetPropIndex(CatID cid) { return GetIndex(m_property[cid]); }
void SetProperty(PropID pid) { m_property[GetCatID(pid)] = pid; }
void ClearProperty(PropID pid) { m_property[GetCatID(pid)] = (PropID) EMPTY;}
private:
CatID GetCatID(PropID pid) { return (CatID) (pid & (COUNT_EXTENDED_CatID - 1)); }
int GetIndex(PropID pid) { return pid >> BITS_CatID; }
};
class CHint
{
protected:
const PropID m_pid0; // a property in the hint
CHouse* m_pNewOwner0; // ptr to a would-be owner of the property to meet the hint
CHouse* m_pNext; // the next house to be checked and filled
static CHouse house[COUNT_HOUSES]; // array of the houses
private:
// array of pointers to house owners indexed by PropID
static CHouse* propowner[COUNT_CATEGORIES*COUNT_EXTENDED_CatID];
static int count_solutions; // count of solutions found
// constructor
protected:
CHint(PropID pid0) : m_pid0(pid0) {}
public:
// starting from house specified by m_pNext, seek and assign the
// first eligible houseowner(s) with properties.
//
// return value:
// 0 : failed
// nonzero : successful
//
virtual int AssignPropToNextEligibles() = 0;
virtual void RemovePropFromPrevEligibles() = 0; // undo AssignPropToNextEligibles
virtual void ResetSeekPosition() = 0; // reset the seek to start position
static void PrintOut(); // print out a solution
// helpers
protected:
void RemoveProperty(); // remove property from new owner
int AssignPropertySetNextPos(CHouse* p0, CHouse* pNext);
// property register operations
protected:
static CHouse* GetPropertyOwner(PropID pid) { return propowner[pid]; }
static void RegisterOwnership(PropID pid, CHouse* pOwner)
{
propowner[pid] = pOwner;
}
// counter
public:
static int GetSolutionCount() { return count_solutions; };
private:
static void IncSolutionCount() { count_solutions++; };
// helper
static CHouse* VerifyCurrentSolution(); // verify a solution and check for errors
static void printout();
};
// class for any hint of Known house number
//
class CKnownHouseHint : public CHint
{
private:
CHouse* const m_pKnownHouse;
public:
CKnownHouseHint(HouseID i, PropID pid) : CHint(pid), m_pKnownHouse(&house[i]) {}
private:
virtual int AssignPropToNextEligibles();
virtual void ResetSeekPosition() { m_pNext = m_pKnownHouse; }
virtual void RemovePropFromPrevEligibles() { RemoveProperty(); }
};
// class for any hint that involves Multiple properties
//
class CMultiPropertiesHint : public CHint
{
protected:
const PropID m_pid1; // a property in the hint
CHouse* m_pNewOwner1; // ptr to a would-be owner of the property to meet the hint
// implementations
protected:
virtual void RemovePropFromPrevEligibles();
// constructor
protected:
CMultiPropertiesHint(PropID pid0, PropID pid1) : CHint(pid0), m_pid1(pid1) { }
// helpers
protected:
void ResetSeekPositionToFirstHouse() { m_pNext = &house[HOUSE0]; }
int AssignPropertiesSetNextPos(CHouse* p0, CHouse* p1, CHouse* pNext);
};
// class for the any hint that only involves a Single houseowner
//
class CSingleHouseHint : public CMultiPropertiesHint
{
// constructor
public:
CSingleHouseHint(PropID pid0, PropID pid1) : CMultiPropertiesHint(pid0, pid1) { }
// implementations
private:
virtual int AssignPropToNextEligibles();
virtual void ResetSeekPosition() { ResetSeekPositionToFirstHouse(); }
};
// class for any hint that involves 2 Neighbors Ordered by direction
//
class COrderedNeighborsHint : public CMultiPropertiesHint
{
// constructor
public:
COrderedNeighborsHint(PropID pid0, PropID pid1) : CMultiPropertiesHint(pid0, pid1) {}
// implementations
private:
virtual int AssignPropToNextEligibles();
virtual void ResetSeekPosition() { ResetSeekPositionToFirstHouse(); }
};
// class for any hint that involves 2 Neighbors without a directional restriction
//
class CNeighborsHint : public CMultiPropertiesHint
{
private:
int m_NextReverse; // are the properties to be filled in reverse order?
// constructor
public:
CNeighborsHint(PropID pid0, PropID pid1) : CMultiPropertiesHint(pid0, pid1) { }
// implementations
private:
virtual int AssignPropToNextEligibles();
virtual void ResetSeekPosition()
{
ResetSeekPositionToFirstHouse();
m_NextReverse = 0;
}
};
// class for finding the solutions
//
class CSolver
{
private:
static CHint* hint[]; // array of pointers to CHint objects
static int count_nodes; // count of nodes searched
// operations
public:
static void DoTheWork(); // search driver
// helpers
private:
static void Search(CHint** ppCHint); // search engine
static void PrintEinsteinRiddleDescription();
static void IncNodeCount() { count_nodes++; };
static int GetNodeCount() { return count_nodes; };
};