您的位置:首页 > 其它

ZOJ Problem Set - 1005

2011-06-08 10:37 351 查看
【【搜索题】】

【题目】

Jugs

Time Limit: 1 Second Memory Limit:32768 KB Special Judge

In the movie "Die Hard 3", Bruce Willis and Samuel L. Jackson were confronted with the following puzzle. They were given a 3-gallon jug and a 5-gallon jug and were asked to fill the 5-gallon jug with exactly 4 gallons. This problem
generalizes that puzzle.
You have two jugs, A and B, and an infinite supply of water. There are three types of actions that you can use: (1) you can fill a jug, (2) you can empty a jug, and (3) you can pour from one jug to the other. Pouring from one jug
to the other stops when the first jug is empty or the second jug is full, whichever comes first. For example, if A has 5 gallons and B has 6 gallons and a capacity of 8, then pouring from A to B leaves B full and 3 gallons in A.
A problem is given by a triple (Ca,Cb,N), where Ca and Cb are the capacities of the jugs A and B, respectively, and N is the goal. A solution is a sequence of steps that leaves exactly N gallons in jug B. The possible steps are
fill A

fill B

empty A

empty B

pour A B

pour B A

success
where "pour A B" means "pour the contents of jug A into jug B", and "success" means that the goal has been accomplished.
You may assume that the input you are given does have a solution.
Input
Input to your program consists of a series of input lines each defining one puzzle. Input for each puzzle is a single line of three positive integers: Ca, Cb, and N. Ca and Cb are the capacities of jugs A and B, and N is the goal.
You can assume 0 < Ca <= Cb and N <= Cb <=1000 and that A and B are relatively prime to one another.
Output
Output from your program will consist of a series of instructions from the list of the potential output lines which will result in either of the jugs containing exactly N gallons of water. The last line of output for each puzzle should
be the line "success". Output lines start in column 1 and there should be no empty lines nor any trailing spaces.

Sample Input

3 5 4
5 7 3

Sample Output

fill B
pour B A
empty A
pour B A
fill B
pour B A
success
fill A
pour A B
fill A
pour A B
empty B
pour A B
success


Source: Zhejiang University Local Contest 2001

【题意说明】
给A、B两个空水壶以及它们的容量,用以下3个动作的组合:(1)给一个水壶注满水;(2)把一个水壶中的水倒入另一个水壶直到倒入水壶满或倒出水壶空;(3)把一个水壶的水全数倒空,使得最后B水壶的水量为给定值N。输入A、B水壶容量以及定值N,输出任意一种动作组合。

【解答】


(一)分析:用广度优先搜索解决。广搜树的节点状态为A、B的水量,由初始状态(A,B皆空)开始,以后每一个状态节点都生成它的可行的后继状态节点(注满A、注满B、清空A、清空B、A倒入B、B倒入A),进行广度优先搜索,并保存每个搜索节点的前一个节点。当搜到的某个节点有B水量为N时,根据保存的前一个节点回溯输出这条路径。搜索期间用reach[x][y]表示A水量为x、B水量为y的节点是否被搜过。
(二)代码
//action:1,fill A,2,fill B,10,empty A,20,empty B,12,AB,21,BA
#include<iostream>
#include<queue>
#include<stack>
using namespace std;
//搜索节点
typedef struct node
{
public:
int a,b;//A、B水量
int action;//当前节点执行的动作(1表示注满A,2表示注满B,10表示清空A,20表示清空B,12表示A倒入B,21表示B倒入A)
struct node *prior;//保存其父节点
}Node;
bool reach[1005][1005];//某节点状态是否搜索过
Node sd[1000*1000];
int main()
{
int ca,cb,n,c;
Node d,v;
queue<Node> q;
stack<Node> st;
int i,j,num;
while(cin>>ca>>cb>>n){
for(i=0;i<1005;i++)
for(j=0;j<1005;j++)
reach[i][j]=false;
while(!q.empty())
q.pop();
//初始化根节点的2个子节点(注满A\注满B)
d.a=ca;
d.b=0;
d.action=1;
d.prior=NULL;
q.push(d);
d.a=0;
d.b=cb;
d.action=2;
d.prior=NULL;
q.push(d);
num=0;
//开始搜索
while(!q.empty()){
v=q.front();
q.pop();
if(v.b==n)//找到解决方案
break;
if(reach[v.a][v.b])
continue;
reach[v.a][v.b]=true;
sd[num]=v;
if(v.a==0&&v.b!=0){
if(v.b!=cb){//注满A
d.a=ca;
d.b=v.b;
d.action=1;
d.prior=&sd[num];
q.push(d);
}
if(v.b>ca){//B倒入A,A满
d.a=ca;
d.b=v.b-ca;
d.action=21;
d.prior=&sd[num];
q.push(d);
}
else if(v.b<ca){//B倒入A,B空
d.a=v.b;
d.b=0;
d.action=21;
d.prior=&sd[num];
q.push(d);
}
}
else if(v.b==0&&v.a!=0){
if(v.a!=ca){//注满B
d.a=v.a;
d.b=cb;
d.action=2;
d.prior=&sd[num];
q.push(d);
}
//A倒入B,A空
d.a=0;
d.b=v.a;
d.action=12;
d.prior=&sd[num];
q.push(d);
}
else if(v.a!=0&&v.b!=0){
if(v.a==ca&&v.b!=cb){
//清空A
d.a=0;
d.b=v.b;
d.action=10;
d.prior=&sd[num];
q.push(d);
if(cb-v.b>ca)//A倒入B,A空
{
d.a=0;
d.b=v.b+ca;
d.action=12;
d.prior=&sd[num];
q.push(d);
}
else if(cb-v.b<ca)//A倒入B,B满
{
d.a=ca-(cb-v.b);
d.b=cb;
d.action=12;
d.prior=&sd[num];
q.push(d);
}

}
else if(v.a!=ca&&v.b==cb){
//清空B
d.a=v.a;
d.b=0;
d.action=20;
d.prior=&sd[num];
q.push(d);
//B倒入A,A满
d.a=ca;
d.b=cb-(ca-v.a);
d.action=21;
d.prior=&sd[num];
q.push(d);
}
else if(v.a!=ca&&v.b!=cb){
d.a=ca;
d.b=v.b;
d.action=1;//注满A
d.prior=&sd[num];
q.push(d);
d.a=v.a;
d.b=cb;
d.action=2;//注满B
d.prior=&sd[num];
q.push(d);
d.a=0;
d.b=v.b;
d.action=10;//清空A
d.prior=&sd[num];
q.push(d);
d.a=v.a;
d.b=0;
d.action=20;//清空B
d.prior=&sd[num];
q.push(d);
if(cb-v.b>v.a){//A倒入B,A空
d.a=0;
d.b=v.b+v.a;
d.action=12;
d.prior=&sd[num];
q.push(d);
}
else if(cb-v.b<v.a){//A倒入B,B满
d.a=v.a-(cb-v.b);
d.b=cb;
d.action=12;
d.prior=&sd[num];
q.push(d);
}
if(ca-v.a>v.b){//B倒入A,B空
d.a=v.a+v.b;
d.b=0;
d.action=21;
d.prior=&sd[num];
q.push(d);
}
else if(ca-v.a<v.b){//B倒入A,A满
d.a=ca;
d.b=v.b-(ca-v.a);
d.action=21;
d.prior=&sd[num];
q.push(d);
}
}
}
num++;
}
d=v;
st.push(d);
while(d.prior!=NULL){//将路径回溯,节点保存到栈中
d=*(d.prior);
st.push(d);
}
while(!st.empty()){//栈中节点从头到尾输出
d=st.top();
st.pop();
c=d.action;
if(c==1)
cout<<"fill A"<<endl;
else if(c==2)
cout<<"fill B"<<endl;
else if(c==10)
cout<<"empty A"<<endl;
else if(c==20)
cout<<"empty B"<<endl;
else if(c==12)
cout<<"pour A B"<<endl;
else if(c==21)
cout<<"pour B A"<<endl;

}
cout<<"success"<<endl;
}
return 0;
}
//Accepted


(解于2009/10)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: