SDU--B - Pour Water--2020-02-26

題目描述

  倒水問題 “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); 
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章