題目描述
倒水問題 “fill A” 表示倒滿A杯,"empty A"表示倒空A杯,“pour A B” 表示把A的水倒到B杯並且把B杯倒滿或A倒空。
輸入
輸入包含多組數據。每組數據輸入 A, B, C 數據範圍 0 < A <= B 、C <= B <=1000 、A和B互質。 |
輸出
你的程序的輸出將由一系列的指令組成。這些輸出行將導致任何一個罐子正好包含C單位的水。每組數據的最後一行輸出應該是“success”。輸出行從第1列開始,不應該有空行或任何尾隨空格。 |
樣例輸入
2 7 5 2 7 4 |
樣例輸出
fill B pour B A success fill A pour A B fill A pour A B success |
思路
綜述
這是一個隱式圖問題。構造二維圖,節點的x座標表示A杯中的水量,節點的y座標表示B杯中的水量,從點(0,0)開始廣度優先搜索(即兩個杯子都是空的開始);對於每個點,搜索的方向一共有六個即1)倒滿A杯;2)倒滿B杯;3)A杯倒向B杯;4)B杯倒向A杯;5)倒空A杯;6)倒空B杯
每到達一個點,對該點打上標記。接着遍歷該點的六個方向的點,如果滿足1)沒有被標記過;2)該點可以到達,即杯子不溢出;則記錄一下該點,同時記錄一下上一個點到該點的方式即:0代表success 1代表 倒滿A 2代表倒滿B 3代表B->A 4代表A->B 5倒空A 6 倒空B,並且記錄該點的父節點(也就是上一個點),並且入隊。遍歷完六個方向之後,接下來從隊列中取出一個點,進行上述操作,直到遇到點(x,y),滿足(x==C || y==C);然後藉助每個點都記錄過父節點,回溯到(0,0)依次入棧,再依次出棧得到正確的倒水路線。
主要變量解釋
結構體point:
number(int):本狀態的ID
x(int):代表A杯內的水
y(int):代表B杯內的水
last(int):代表該狀態的上一個狀態的ID
vis(int):二維數組,用於標記點是否到達過
qq(<queue>):用於廣度優先搜索記錄遍歷過的點
way(<stack>):用於回溯到起點的棧
next(int):全局變量,用於目前標記所到達的點,是全局的第幾個點
過程
step1:記錄P(0).x=P(0).y=P(0).number=P(0).last=0;P[0].code=0打標記:vis(0,0)=1;該點入隊qq
step2:從隊列qq中pop出一個元素 now進入step3
step3:依次遍歷該點的六個方向,每遍歷到一個點nextp進入step4,若遍歷結束進入step2;
step4:判斷該點nextp是否滿足1)沒有被標記過;2)該點可以到達,即杯子不溢出;若不滿足進入step3;若滿足則進入step5
step5:記錄該點爲P[next](next詳見主要變量解釋);記錄P[next].last=now.number;記錄一下,上一個點到該點的方式code;對該點打上標記vis[P[next].x,P[next].y]=1;進入step6
step6:判斷該點如果該點滿足(x==C || y==C);則進入step7;否則進入step3;
step7:利用棧way來從目標點回溯到起點(0,0)依次入棧
step8:棧中元素依次pop 得到正確的結果
代碼
#include <iostream>
#include <stack>
#include <queue>
#include <string.h>
using namespace std;
struct point{
int x,y;//x代表A杯內的水 y代表B杯內的水
int number;//本狀態的ID
int last;//代表該狀態的上一個狀態的ID
int code;//0代表success 1代表 倒滿A 2代表倒滿B 3代表B->A 4代表A->B 5倒空A 6 倒空B
}P[5000];
void solve(int A,int B,int C){
int vis[105][105];//用於記錄某個狀態是否到達過
int flag=0;
int i,j,k,l;
int pnode;//記錄父節點位置
int next=0;
int goal;
//初始化
memset(vis,0,sizeof(int)*105*105);
stack<point> way;
queue<point> qq;
P[0].x=0;
P[0].y=0;
P[0].number=0;
P[0].last=0;
P[0].code=0;
vis[P[0].x][P[0].y]=1;
qq.push(P[0]);
while(!flag){
point now = qq.front();
qq.pop();
pnode = now.number;
//0代表success +1代表 倒滿A 2代表倒滿B 3代表B->A 4代表A->B 5倒空A 6 倒空B
for(i=1;i<=6;i++){
point nextp;
if(i==1){
nextp.x = A;
nextp.y = now.y;
if(!vis[nextp.x][nextp.y]){
vis[nextp.x][nextp.y]=1;
next++;
P[next].x = nextp.x;
P[next].y = nextp.y;
P[next].code = 1;
P[next].number = next;
P[next].last = pnode;
nextp.code=1;
nextp.last = pnode;
nextp.number = next;
qq.push(nextp);
if(P[next].x==C || P[next].y==C){
flag=1;
goal=next;
break;
}
}
}else if(i==2){
nextp.x = now.x;
nextp.y = B;
if(!vis[nextp.x][nextp.y]){
vis[nextp.x][nextp.y]=1;
next++;
P[next].x = nextp.x;
P[next].y = nextp.y;
P[next].code = 2;
P[next].number = next;
P[next].last = pnode;
nextp.code=2;
nextp.last = pnode;
nextp.number = next;
qq.push(nextp);
if(P[next].x==C || P[next].y==C){
flag=1;
goal=next;
break;
}
}
}else if(i==3){
if(now.y==0)continue;//B空
if(now.x==A)continue;//A滿
if(now.y>=A-now.x){//B中的水可以倒滿A
nextp.x = A;
nextp.y = now.y - (A-now.x);
}else if(now.y<A-now.x){//B中的水不可以倒滿A
nextp.x = now.x+now.y;
nextp.y = 0;
}
if(!vis[nextp.x][nextp.y]){
vis[nextp.x][nextp.y]=1;
next++;
P[next].x = nextp.x;
P[next].y = nextp.y;
P[next].code = 3;
P[next].number = next;
P[next].last = pnode;
nextp.code=3;
nextp.last = pnode;
nextp.number = next;
qq.push(nextp);
if(P[next].x==C || P[next].y==C){
flag=1;
goal=next;
break;
}
}
}else if(i==4){
if(now.y==B)continue;//B滿
if(now.x==0)continue;//A空
if(now.x>=B-now.y){//A中的水可以倒滿B
nextp.x = now.x - (B-now.y);
nextp.y = B;
}else if(now.x<B-now.y){//A中的水不可以倒滿B
nextp.x = 0;
nextp.y = now.x + now.y;
}
if(!vis[nextp.x][nextp.y]){
vis[nextp.x][nextp.y]=1;
next++;
P[next].x = nextp.x;
P[next].y = nextp.y;
P[next].code = 4;
P[next].number = next;
P[next].last = pnode;
nextp.code=4;
nextp.last = pnode;
nextp.number = next;
qq.push(nextp);
if(P[next].x==C || P[next].y==C){
flag=1;
goal=next;
break;
}
}
}else if(i==5){
nextp.x = 0;
nextp.y = now.y;
if(!vis[nextp.x][nextp.y]){
vis[nextp.x][nextp.y]=1;
next++;
P[next].x = nextp.x;
P[next].y = nextp.y;
P[next].code = 5;
P[next].number = next;
P[next].last = pnode;
nextp.code=5;
nextp.last = pnode;
nextp.number = next;
qq.push(nextp);
if(P[next].x==C || P[next].y==C){
flag=1;
goal=next;
break;
}
}
}else if(i==6){
nextp.x = now.x;
nextp.y = 0;
if(!vis[nextp.x][nextp.y]){
vis[nextp.x][nextp.y]=1;
next++;
P[next].x = nextp.x;
P[next].y = nextp.y;
P[next].code = 6;
P[next].number = next;
P[next].last = pnode;
nextp.code=6;
nextp.last = pnode;
nextp.number = next;
qq.push(nextp);
if(P[next].x==C || P[next].y==C){
flag=1;
goal=next;
break;
}
}
}
}
}
while(goal!=0){
way.push(P[goal]);
goal = P[goal].last;
}
way.push(P[goal]);
while(!way.empty()){
if(way.top().code==1) cout<<"fill A"<<endl;
if(way.top().code==2) cout<<"fill B"<<endl;
if(way.top().code==3) cout<<"pour B A"<<endl;
if(way.top().code==4) cout<<"pour A B"<<endl;
if(way.top().code==5) cout<<"empty A"<<endl;
if(way.top().code==6) cout<<"empty B"<<endl;
way.pop();
}
cout<<"success"<<endl;
}
int main(){
int a,b,c;
//輸入杯子容量和目標水量
while(cin>>a>>b>>c)
solve(a,b,c);
}