倒水問題(程式設計藝術與方法個人實驗)
阿新 • • 發佈:2020-12-12
技術標籤:筆記
問題描述:給定2個沒有刻度容器,對於任意給定的容積,求出如何只用兩個瓶裝出L升的水,如果可以,輸出步驟,如果不可以,請輸出No Solution。
①實驗要求:
(1)求出如何只用兩個瓶裝出L升的水,如果可以,輸出步驟,如果不可以,請輸出No Solution.
題目分析:
這一題可以使用BFS的思想來做。
對於A、B兩個瓶子,在任何時刻,“倒水” 無非6種操作:
1.倒滿A;
2.倒滿B;
3.倒空A;
4.倒空B;
5.A往B倒;
6.B往A倒;
本題我沒用採用STL的佇列,通過在表示每個狀態的節點中加入父結點指標,當找到可行解時,通過父結點指標回溯,已達到輸出每一步的結果。同時對兩容器容積進行特判,因為如果不互質則無解。同時所量容積不能超過兩容器總體積之和。
接下來是程式碼實現:
#include <iostream>
#include <vector>
#include <stack>
#include <string>
#include <algorithm>
using namespace std;
typedef struct node Node;
struct node{
int step; //記錄上一節點所採取的步驟
int a; //當前a容器的液體的體積
int b; //當前b容器的液體的體積
int pre; //記錄父節點
};
int a, b, L, ans; //兩容器容積和所需體積
int visited[200][200]; //記錄該節點是否被訪問
vector<string> v; //不同的倒水策略
vector<Node> Ans; //用於儲存BFS節點
stack<Node> s; //用於輸出移動步驟
void initialize(){ //初始化所需資訊
v.push_back("a to b"); //step0
v.push_back("b to a"); //step1
v.push_back("Fill a" ); //step2
v.push_back("Fill b"); //step3
v.push_back("Empty a"); //step4
v.push_back("Empty b"); //step5
cout << "請輸入兩個容器的體積和所需液體體積:" << endl;
cin >> a >> b >> L;
cout << "容器的體積分別為: " << a << " " << b << endl;
cout << "所需液體體積為:" << L << endl;
Node n; //第一個節點,無父節點
n.pre = -1;
n.a = 0;
n.b = 0;
n.step = -1;
Ans.push_back(n);
}
bool rp(int a, int b){
int temp;
if(a < b)
swap(a, b);
while(b){
temp = a % b;
a = b;
b = temp;
}
if(a == 1)
return true;
else
return false;
}
int BFS(){
for(int i = 0; i < Ans.size(); i++){
Node p = Ans[i];
Node t;
if(a + b < L)
break;
if(!rp(a,b))
break;
if(p.a == L || p.b == L || (p.a + p.b == L)){ //找到可行解退出
ans = i;
return 1;
}
if(p.a && p.b < b){ //a往b中倒水
if((p.b >= b - p.a) && !visited[p.a - b + p.b][b]){ //倒滿b後a有剩餘
t.a = p.a - b + p.b;
t.b = b;
t.pre = i;
t.step = 0;
Ans.push_back(t);
}
else if(!visited[0][p.b + p.a]){ //a沒有剩餘
t.a = 0;
t.b = p.b + a;
t.pre = i;
t.step = 0;
Ans.push_back(t);
}
}
if(p.b && p.a < a){ //b往a中倒水
if((p.a >= a - p.b) && !visited[a][p.b - a + p.a]){ //倒完後b中有剩餘
t.a = a;
t.b = p.b - a + p.a;
t.pre = i;
t.step = 1;
Ans.push_back(t);
}
else if(!visited[p.a + p.b][0]){ //b沒有剩餘
t.a = p.a + p.b;
t.b = 0;
t.pre = i;
t.step = 1;
Ans.push_back(t);
}
}
if(p.a < a && !visited[a][p.b]){ //倒滿a
t.a = a;
t.b = p.b;
t.pre = i;
t.step = 2;
Ans.push_back(t);
}
if(p.b < b && !visited[p.a][b]){ //倒滿b
t.a = p.a;
t.b = b;
t.pre = i;
t.step = 3;
Ans.push_back(t);
}
if(p.a && !visited[0][p.b]){ //清空a
t.a = 0;
t.b = p.b;
t.pre = i;
t.step = 4;
Ans.push_back(t);
}
if(p.b && !visited[p.a][0]){ //清空b
t.a = p.a;
t.b = 0;
t.pre = i;
t.step = 5;
Ans.push_back(t);
}
}
return 0;
}
void show(){
int count = 1;
Node q = Ans[ans];
while(q.pre != -1){
s.push(q);
q = Ans[q.pre];
}
while(!s.empty()){
q = s.top();
cout << "step " << count << " : "<< v[q.step] << endl;
count++;
s.pop();
}
}
int main(){
initialize();
if(!BFS())
cout << "No Solution!" << endl;
else
show();
return 0;
}
執行結果示例: