穷举法解倒酒问题
mop上见到的问题:有两个容量为8两的瓶子,各装满酒。有一只杯子。要把这16两酒平均分给4个人喝。问怎么样倒酒。(后附能在XX时间内解出的的智商有N高云云。。。)俺智商较低,借助程序求解。思路:穷举法#$#~#@!容器有三种。瓶子和杯子有最大容量,并且可以倒出也可以倒入。“人”没有最大容量,可以倒出不能倒入。人容纳的酒量大于4的状态就算game over。16两酒的分布状态可用一个唯一的哈希值表示
mop上见到的问题:有两个容量为8两的瓶子,各装满酒。有一只杯子。要把这16两酒平均分给4个人喝。问怎么样倒酒。(后附能在XX时间内解出的的智商有N高云云。。。)
俺智商较低,借助程序求解。
思路:穷举法#$#~#@!
容器有三种。瓶子和杯子有最大容量,并且可以倒出也可以倒入。“人”没有最大容量,可以倒出不能倒入。人容纳的酒量大于4的状态就算game over。
16两酒的分布状态可用一个唯一的哈希值表示。使用情况是瓶子用4位,杯子用3位(2位都可以了),人用3位。递归时把当前状态放进列表中。每种分布状态在列表中可能出现的值有:已访问,死亡,成功。已访问的结点在下一层递归将被忽略。若下一层的所有可能方案均返回死亡,则此层也被置为死亡。这样就确保了不会走回头路,因此此算法是非常快的。
最后输出的是最少步骤的方案。
// BottleGame.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdio.h"
#include "conio.h"
#include <map>
#include <vector>
using namespace std;
class CContainer
{
protected:
int m_nCapability;
int m_nWeight;
char* m_pszName;
public:
CContainer(char *name, int C, int W)
{
m_nCapability = C;
m_nWeight = W;
m_pszName = name;
};
void SetWeight(int w) { m_nWeight = w; }
int GetWeight(void) { return m_nWeight; }
int Pour(CContainer* pReceiver)
{
int n = GetWeight();
if (n > pReceiver->GetCapability() - pReceiver->GetWeight())
n = pReceiver->GetCapability() - pReceiver->GetWeight();
pReceiver->SetWeight(pReceiver->GetWeight() + n);
SetWeight(GetWeight() - n);
return n;
};
void UnPour(CContainer* pReceiver, int n)
{
pReceiver->SetWeight(pReceiver->GetWeight() - n);
SetWeight(GetWeight() + n);
};
int GetCapability(void) { return m_nCapability; }
char* GetName(void) { return m_pszName; }
public:
virtual bool CanPour(void) = 0;
virtual int GetBits(void) = 0;
virtual bool Die(void) = 0;
};
class CBottle : public CContainer
{
public:
CBottle(char *name) : CContainer(name, 8, 8)
{
}
virtual bool CanPour(void) { return true; }
virtual int GetBits(void) { return 4; }
virtual bool Die(void) { return false; }
};
class CCup : public CContainer
{
public:
CCup(char *name = "cup") : CContainer(name, 3, 0)
{
}
virtual bool CanPour(void) { return true; }
virtual int GetBits(void) { return 3; }
virtual bool Die(void) { return false; }
};
class CMan : public CContainer
{
public:
CMan(char *name) : CContainer(name, 100, 0)
{
}
virtual bool CanPour(void) { return false; }
virtual int GetBits(void) { return 3; }
virtual bool Die(void) { return GetWeight() > 4; }
};
enum visited_status {
none,
visited,
dead,
success
};
typedef struct _tagMethod {
CContainer* pPourer;
CContainer* pReceiver;
int n;
} Method;
map<int/*key*/, visited_status> PathArray;
vector<CContainer*> Objs;
Method Methods[100];
int min_steps = 1000;
int get_status_hash(void)
{
int n = 0, nLastBits = 0;
for ( vector<CContainer*>::iterator it = Objs.begin();
it != Objs.end(); ++it )
{
n <<= nLastBits;
n += (*it)->GetWeight();
nLastBits = (*it)->GetBits();
}
return n;
}
void dump_all(void)
{
for ( vector<CContainer*>::iterator it = Objs.begin();
it != Objs.end(); ++it )
{
printf("%8d", (*it)->GetWeight());
}
printf("/n");
}
enum MethodResult
{
mrSucceed,
mrDie,
mrOverflow
};
enum MethodResult try_method(int level)
{
CContainer *pPourer, *pReceiver;
if (level >= min_steps) return mrOverflow; // exceeded
if (level >= 300) return mrOverflow;
int hash;
map<int, visited_status>::iterator it;
bool bAllDie = true;
for ( vector<CContainer*>::iterator itPourer = Objs.begin();
itPourer != Objs.end(); ++itPourer )
{
pPourer = *itPourer;
if (!pPourer->CanPour()) continue;
for ( vector<CContainer*>::iterator itReceiver = Objs.begin();
itReceiver != Objs.end(); ++itReceiver )
{
pReceiver = *itReceiver;
if (pReceiver == pPourer) continue;
if (pReceiver->GetCapability() == pReceiver->GetWeight()) continue; // full
int n = pPourer->Pour(pReceiver);
if (pReceiver->Die())
{
pPourer->UnPour(pReceiver, n);
continue;
}
Methods[level].pPourer = pPourer;
Methods[level].pReceiver = pReceiver;
Methods[level].n = n;
hash = get_status_hash();
it = PathArray.find(hash);
if (it != PathArray.end())
{
if (it->second == success)
{
min_steps = level;
pPourer->UnPour(pReceiver, n);
return mrSucceed;
}
if (it->second == dead || it->second == visited)
{
pPourer->UnPour(pReceiver, n);
continue; // die
}
}
// dump_all();
PathArray[hash] = visited;
switch(try_method(level + 1))
{
case mrSucceed:
if (PathArray[hash] == visited) PathArray.erase(hash);
pPourer->UnPour(pReceiver, n);
return mrSucceed;
case mrDie:
PathArray[hash] = dead;
break;
case mrOverflow:
bAllDie = false;
break;
}
if (PathArray[hash] == visited) PathArray.erase(hash);
pPourer->UnPour(pReceiver, n);
}
}
if (bAllDie)
{
hash = get_status_hash();
PathArray[hash] = dead;
return mrDie;
}
return mrOverflow;
}
int _tmain(int argc, _TCHAR* argv[])
{
// init
Objs.push_back(new CBottle("Bottle1"));
Objs.push_back(new CBottle("Bottle2"));
Objs.push_back(new CCup("Cup"));
Objs.push_back(new CMan("A"));
Objs.push_back(new CMan("B"));
Objs.push_back(new CMan("C"));
Objs.push_back(new CMan("D"));
int hash = (((((4 << 3) + 4) << 3) + 4) << 3) + 4;
PathArray[hash] = success;
// try
enum MethodResult Res = try_method(0);
// print result
if (Res == mrSucceed)
{
for ( int i = 0; i <= min_steps; i++ )
{
printf("%s -> %s : %d/n",
Methods[i].pPourer->GetName(),
Methods[i].pReceiver->GetName(),
Methods[i].n
);
}
}
// clean up
for ( vector<CContainer*>::iterator it = Objs.begin();
it != Objs.end(); ++it ) delete (*it);
printf("/npress any key.../n");
getch();
return 0;
}
更多推荐
所有评论(0)