窮舉法解倒酒問題

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;
}

發佈了41 篇原創文章 · 獲贊 2 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章