算法谜题——三个水壶问题
問題:有一個(gè)充滿水的8品脫的水壺和兩個(gè)空水壺(容積分別是5品脫和3品脫)。通過將水壺完全倒?jié)M水和將水壺的水完全倒空這兩種方式,在其中的一個(gè)水壺中得到4品脫的水。
解法:可以把每次三個(gè)水壺中水的量組成一個(gè)狀態(tài),比如初始狀態(tài)為008,對應(yīng)第一個(gè)水壺0品脫水,第二個(gè)水壺0品脫水,第三個(gè)水壺8品脫水。對題目的狀態(tài)空間圖進(jìn)行廣度優(yōu)先遍歷。當(dāng)表示狀態(tài)的數(shù)字中出現(xiàn)4時(shí),即求出答案。
1、為了打印出倒水的過程,需要聲明一個(gè)前置狀態(tài)保存當(dāng)前狀態(tài)由哪個(gè)狀態(tài)轉(zhuǎn)換而來,然后就可以回溯到初始狀態(tài),打印出倒水過程。相當(dāng)于樹中的父結(jié)點(diǎn)。
2、可以聲明一個(gè)map表,保存已有的狀態(tài),對已有的狀態(tài),就不再向下繼續(xù)遍歷,這樣可以節(jié)省求解時(shí)間。
3、因?yàn)槭菑V度優(yōu)先遍歷,所以第一次解得的答案所需的倒水的次數(shù)最少,解為最優(yōu)解。
#include <iostream> #include <vector> #include <map> #define MaxFirst 3 #define MaxSecond 5 #define MaxThird 8 using namespace std;class State { public:int second;int num[3];State* preState;static map<int,int> mapping;public:State(int first,int second,int third){num[0]=first;num[1]=second;num[2]=third; }void init(){ mapping[0]=MaxFirst;mapping[1]=MaxSecond;mapping[2]=MaxThird;}bool canPour(int from,int to)//判斷是否可以從from水壺中倒水到to水壺中{if(num[from]==0){return false;}if(num[to]==mapping[to]){return false;}else {return true;}}void pour(int from,int to)//倒水過程{if(num[from]+num[to]>mapping[to]){num[from]=num[from]-(mapping[to]-num[to]);num[to]=mapping[to];}else{num[to]=num[to]+num[from];num[from]=0;}}}; map<int,int> State::mapping;int main() {map<int,int> states;State *start=new State(0,0,8);start->init();State *state=start;State *endState=new State(8,8,8);//只有獲得解endState才會改變,賦值全為8為了方便判斷是否獲得最終解vector<State> action;//保存所有狀態(tài)對象action.push_back(*start);//把初始狀態(tài)先加入隊(duì)列中int n=0;do{for(int i=0;i<3;i++)//雙層循環(huán)為從i水壺中倒水入j水壺中{for(int j=0;j<3;j++){if(i!=j){if(state->canPour(i,j)){state->pour(i,j);if(states[state->num[0]*100+state->num[1]*10+state->num[2]]==0)//如果該狀態(tài)不在hash表中,即為第一次出現(xiàn)該狀態(tài){states[state->num[0]*100+state->num[1]*10+state->num[2]]++;(state->preState)=new State(action[n]);action.push_back(*state);if(state->num[0]==4||state->num[1]==4||state->num[2]==4)//獲得解{endState=state;i=4;break; }}}}*state=action[n];} }n++;}while(endState->num[0]==8&&endState->num[1]==8&& n<action.size());cout<<endState->num[0]<<" "<<endState->num[1]<<" "<<endState->num[2]<<endl;state=endState;do{state=state->preState;cout<<state->num[0]<<" "<<state->num[1]<<" "<<state->num[2]<<endl; }while(state->num[2]!=8);return 0; }
運(yùn)行結(jié)果如圖,從下往上即為倒水的過程
如果需要倒出水壺含7品脫的情況,把
if(state->num[0]==4||state->num[1]==4||state->num[2]==4)中的4改成7,運(yùn)行出結(jié)果如下:
總結(jié)
以上是生活随笔為你收集整理的算法谜题——三个水壶问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 计算机程序栏怎样重叠,win10系统下任
- 下一篇: 【详解】指令系统中跳转指令与OF,SF,