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



发布了29 篇原创文章 · 获赞 14 · 访问量 1269

猜你喜欢

转载自blog.csdn.net/weixin_44552961/article/details/104631336
今日推荐