poj 3414 Pots(认为是一道很好的bfs题目)

来源:互联网 发布:php简单论坛源码 编辑:程序博客网 时间:2024/06/12 00:08
Pots
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 7783 Accepted: 3261 Special Judge

Description

You are given two pots, having the volume of A and B liters respectively. The following operations can be performed:

  1. FILL(i)        fill the pot i (1 ≤ i ≤ 2) from the tap;
  2. DROP(i)      empty the pot i to the drain;
  3. POUR(i,j)    pour from pot i to pot j; after this operation either the potj is full (and there may be some water left in the pot i), or the poti is empty (and all its contents have been moved to the pot j).

Write a program to find the shortest possible sequence of these operations that will yield exactlyC liters of water in one of the pots.

Input

On the first and only line are the numbers A, B, andC. These are all integers in the range from 1 to 100 and C≤max(A,B).

Output

The first line of the output must contain the length of the sequence of operationsK. The following K lines must each describe one operation. If there are several sequences of minimal length, output any one of them. If the desired result can’t be achieved, the first and only line of the file must contain the word ‘impossible’.

Sample Input

3 5 4

Sample Output

6FILL(2)POUR(2,1)DROP(1)POUR(2,1)FILL(2)POUR(2,1)
 

/*题目大意: 有二个水壶,对水壶有三种操作: 1)FILL(i),将i水壶的水填满; 2)DROP(i),将水壶i中的水全部倒掉; 3)POUR(i,j)将水壶i中的水倒到水壶j中,若水壶 j 满了,则 i 剩下的就不倒了;

问进行多少步操作,并且怎么操作,输出操作的步骤,两个水壶中至少其中一个壶的水可以达到C这个水量。如果不可能则输出impossible。

初始时两个水壶是空的,没有水。 样例中的1代表i,2代表j;拿样例举个栗子:input:3 5 4 //i(用1表示)水壶的容量是3,j(用2表示)水壶的容量是5,要求两个水壶中至少其中一个壶的水可以达到4这个水量0utput:6//需要经过的步数FILL(2) //把j水壶填满,此时j==5;POUR(2,1)//把j水壶中的水倒到i水壶,则此时i==3,j==5-3==2DROP(1)//倒掉i水壶中的水,则此时i==0,j==2POUR(2,1)//把j水壶中的水倒到i水壶,则此时i==2,j==0FILL(2)//把j水壶填满,此时j==5;POUR(2,1)//把j水壶中的水倒到i水壶,则此时i==3,j==5-1==4(满足条件)算法分析:1. 找出状态转移方程. 2. 难点是判重和状态的保存. 判重用的是visited[x][y]二维数组, A为容量x, B为容量y时标记已访问;当再次A为容量x, B为容量y时,不再重复搜索(剪枝). 至于状态的保存用的是一个结构体 struct Step{ int cnt; //走的步数 int prex, prey; //前一步的i,j分别的容量prex, prey int preflag; //前一步到本步骤执行的操作标志};

后面的实现具体看代码.

*/

#include<iostream>#include<queue>#include<stack>#include<cstring>using namespace std;int a,b,c;struct pots//存储每一步当前水壶i,j的水量{    int x,y;    pots(int xx,int yy){x=xx;y=yy;}};struct Step{    int cnt;//走的步数    int prex,prey;//前一步水壶i,j的水量    int preflag;//前一步到本步骤执行的操作标志};bool visited[102][102];//判断“i的水量为x, j的水量为y”时是否已访问过;当再次i的水量为x, j的水量为y时,不再重复搜索(剪枝)Step step[102][102];queue<pots>q;int endx,endy;void savestate(int x,int y,int prex,int prey,int flag) //此函数用来保存当前这一步的所有状态(包括 步数,前一步水壶i,j的水量,前一步到本步骤执行的操作标志){    q.push(pots(x,y));    step[x][y].cnt=step[prex][prey].cnt+1;    step[x][y].prex=prex;    step[x][y].prey=prey;    step[x][y].preflag=flag;}int bfs()//搜索{    memset(visited,0,sizeof(visited));    memset(step,0,sizeof(step));    q.push(pots(0,0));    while(q.size()) {        pots v=q.front();        q.pop();        if(v.x==c||v.y==c)//如果满足条件,终止搜索        {            endx=v.x;            endy=v.y;            break;        }    visited[v.x][v.y]=1;    if(v.x<a&&!visited[a][v.y]) savestate(a,v.y,v.x,v.y,0);//fill a    if(v.y<b&&!visited[v.x][b]) savestate(v.x,b,v.x,v.y,1);//fill b    if(v.x>0&&!visited[0][v.y]) savestate(0,v.y,v.x,v.y,2);//drop a    if(v.y>0&&!visited[v.x][0]) savestate(v.x,0,v.x,v.y,3);//drop b    if(v.x>0)//pour a to b    {        if(v.x<b-v.y&&!visited[0][v.x+v.y]) savestate(0,v.x+v.y,v.x,v.y,4);        else if(v.x>=b-v.y&&!visited[v.x-(b-v.y)][b]) savestate(v.x-(b-v.y),b,v.x,v.y,5);    }    if(v.y>0)//pour b to a    {        if(v.y<a-v.x&&!visited[v.x+v.y][0]) savestate(v.x+v.y,0,v.x,v.y,6);        else if(v.y>=a-v.x&&!visited[a][v.y-(a-v.x)]) savestate(a,v.y-(a-v.x),v.x,v.y,7);    } } return step[endx][endy].cnt;//返回步数}void findpath()//输出路径{    stack<int>s;//用栈来存储,很巧妙!    int x=endx;    int y=endy;    while(!(x==0&&y==0))    {        s.push(step[x][y].preflag);        int tempx=step[x][y].prex;        int tempy=step[x][y].prey;        x=tempx;y=tempy;    }    while(s.size())    {        int v=s.top();        s.pop();        switch(v)        {            case 0:            cout<<"FILL(1)"<<endl;break;            case 1:            cout<<"FILL(2)"<<endl;break;            case 2:            cout<<"DROP(1)"<<endl;break;            case 3:            cout<<"DROP(2)"<<endl;break;            case 4:            case 5:            cout<<"POUR(1,2)"<<endl;break;            case 6:            case 7:            cout<<"POUR(2,1)"<<endl;break;        }    }}int main(){    cin>>a>>b>>c;    int ret=bfs();    if(ret)    {        cout<<ret<<endl;        findpath();    }    else cout<<"impossible"<<endl;    return 0;}

原创粉丝点击