BFS+模拟-Pots POJ - 3414

BFS+模拟-Pots POJ - 3414

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

FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap;
DROP(i) empty the pot i to the drain;
POUR(i,j) pour from pot i to pot j; after this operation either the pot j is full (and there may be some water left in the pot i), or the pot i 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 exactly C liters of water in one of the pots.

Input
On the first and only line are the numbers A, B, and C. 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 operations K. 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
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

题意:
有两个空杯子A(1),B(2),输入第一个杯子A的容量和第二个杯子B的容量以及一个常数C,每次有3种操作选择:
①、FILL(i):将第i杯装满水。
②、DROP(i) :将第i杯倒空。
③、POUR(i,j) :将第i杯中的水倒入第j杯中(能倒多少是多少,可以有剩余)。
问最少需要多少次,才能使至少其中一个杯子的水超过C,同时输出操作路径。

思路:
bfs,分六种情况入队:FILL(1)、FILL(2)、DROP(1)、DROP(2)、POUR(1,2)、POUR(2,1)。
用优先队列步数少的先出队,难点在于回溯,记录最短的操作路径。
用queue的话pop出去的点就找不回来了, 无法路径输出, 所以看到路径输出, 就要想到用数组或者vector!

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f
#define ME0(x) memset(x,0,sizeof(x))
using namespace std;
int a,b,c;
int flag=0;//初始化不能成功
int total=0;//总共操作了几次,也是每个操作步骤的下标
int id[105*105];//保存正确路径的下标
int vis[105][105];//标记A、B当前水量状态是否入队过
char op[][10]={"0","FILL(1)","FILL(2)", "DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};//最后的输出
struct node
{
    int no;//当前下标
    int k1,k2;//杯中剩余的水
    int op;//操作
    int step;//步数
    int pre;//前一步的下标,因为要输出操作路径,而优先队列无法完成,故要记录前驱结点
    bool operator<(const node &c)const//步数小的先出队
    {
        return step>c.step;//>说明:若当前step大返回一个真值,让优先队列进行排序操作
    }
};
priority_queue<node>q;//q用来操作,而数组v用来记录路径
node now,next;
vector<node> v;
void print(int i)//输出格式
{
    int j=0;
    while(v[i].no)
    {
        id[j++]=v[i].no;//储存正确路径的下标
        i=v[i].pre;
    }
    for(i=j-1; i>=0; i--)//按照下标输出操作
    {
        cout<<op[v[id[i]].op]<<endl;
    }
}
void bfs()
{
    now.k1=0,now.k2=0,now.op=0,now.pre=0,now.step=0,now.no=0;//初始化第一个结点状态
    vis[now.k1][now.k2]=1;
    q.push(now);
    v.push_back(now);
    while(!q.empty())
    {
        now=q.top();
        q.pop();
        if(now.k1==c||now.k2==c)//满足条件
        {
            flag=1;
            cout<<now.step<<endl;//输出步数
            print(now.no);//输出格式
            break;
        }
        for(int i=1; i<=6; i++)//6种操作op
        {
            if(i == 1) //fill(1)
            {
                next.k1 = a;
                next.k2 = now.k2;
            }
            else if(i == 2) //fill(2)
            {
                next.k1 = now.k1;
                next.k2 = b;
            }
            else if(i == 3) //drop(1)
            {
                next.k1 = 0;
                next.k2 = now.k2;
            }
            else if(i == 4) // drop(2);
            {
                next.k1 = now.k1;
                next.k2 = 0;
            }
            else if(i == 5) //pour(1,2)
            {
                if(now.k1+now.k2 <= b) //如果不能够装满 b
                {
                    next.k1 = 0;
                    next.k2 = now.k1+now.k2;
                }
                else //如果能够装满 b
                {
                    next.k1 = now.k1+now.k2-b;
                    next.k2 = b;
                }
            }
            else if(i == 6) // pour(2,1)
            {
                if(now.k1+now.k2 <= a) //如果不能够装满 a
                {
                    next.k1 = now.k1+now.k2;
                    next.k2 = 0;
                }
                else //如果能够装满 b
                {
                    next.k1 = a;
                    next.k2 = now.k1+now.k2-a;
                }
            }
            next.op=i;//第i个操作完后,将其的操作序号更新到下一个结点准备将其入队
            if(!vis[next.k1][next.k2])
            {
                total++;
                next.no=total;
                vis[next.k1][next.k2]=1;
                next.step=now.step+1;
                next.pre=now.no;
                v.push_back(next);
                q.push(next);
            }
        }
    }
    if(flag==0)
        cout<<"impossible"<<endl;
}

int main()
{
    ME0(vis);
    cin>>a>>b>>c;
    bfs();
}

总结:

  1. vis数组确定状态
  2. 优先队列重载"<"
  3. vector数组存储node
  4. BFS回溯+模拟输出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值