POJ 3414 Pots 【bfs】【路径打印】

本文介绍了一种解决两桶水问题的算法,通过BFS(广度优先搜索)找到从给定容量的两个桶中获取指定水量的最短步骤。文章详细解释了DROP、FILL和POUR三种操作,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Pots

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 22868 Accepted: 9707 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 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)

Source

Northeastern Europe 2002, Western Subregion

题意:

有两个桶,容量分别为a和b。最初状态下,两个桶并没有放水。

现在有三个操作   1:  DROP i    将i桶内的水全部倒掉

                               2:FILL i        将i桶装满水

                               3:POUR(I,J)   将j桶内的水倒入i中,即将溢出时停止倒水。(不会有水的损耗)

问你再最少在第几步操作时,其中一个桶内的水为C,并输出操作步骤

 

两个桶内的水可看为(x,y) 即可以看成是平面上的一个点,从而记录访问情况。

这里用path数组记录每一个操作的上一个操作的坐标。从而实现路径记录,输出时反向输出即可。

 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
#define LL long long
#define M(a,b) memset(a,b,sizeof(a))
const int MAXN = 1e3+5;
const int INF =  0x3f3f3f3f;
int a,b,c;
int len;
struct Node
{
    char c;///记录操作类型
    int i,j;
    int from;///记录上一个操作的下标
} path[MAXN];///记录路径
int vis[MAXN][MAXN];///记录点的访问情况
queue<pair<pair<int,int>,int> >q;
int bfs(int x,int y)
{
    vis[x][y] = 1;
    q.push(make_pair(make_pair(x,y),len));///len代表现在此操作的下标
    while(!q.empty())
    {
        int x1 = q.front().first.first;
        int y1 = q.front().first.second;
        int temp = q.front().second;
        //printf("x==%d y==%d\n",x1,y1);
        if(x1==c||y1==c)
        {
            return temp;
        }
        q.pop();

        if(vis[x1][0]==0)///DROP操作
        {
            vis[x1][0] = 1;
            len ++;
            path[len].c ='D';
            path[len].i = 2;
            path[len].from = temp;
            q.push(make_pair(make_pair(x1,0),len));
        }
        if(vis[0][y1]==0)
        {
            len ++;
            vis[0][y1] = 1;
            path[len].c ='D';
            path[len].i = 1;
            path[len].from = temp;
            q.push(make_pair(make_pair(0,y1),len));
        }
        if(vis[a][y1]==0)///FILL操作
        {
            len ++;
            vis[a][y1] = 1;
            path[len].c ='F';
            path[len].i = 1;
            path[len].from = temp;
            q.push(make_pair(make_pair(a,y1),len));
        }
        if(vis[x1][b]==0)
        {
            len ++;
            vis[x1][b] = 1;
            path[len].c ='F';
            path[len].i = 2;
            path[len].from = temp;
            q.push(make_pair(make_pair(x1,b),len));
        }
        if(x1+y1<=a)///POUR 操作
        {
            if(vis[x1+y1][0]==0)
            {
                len ++;
                vis[x1+y1][0] = 1;
                path[len].c ='P';
                path[len].i = 2;
                path[len].j = 1;
                path[len].from = temp;
                q.push(make_pair(make_pair(x1+y1,0),len));
            }
        }
        else
        {
            if(vis[a][y1-a+x1]==0)
            {
                len ++;
                vis[a][y1-a+x1] = 1;
                path[len].c ='P';
                path[len].i = 2;
                path[len].j = 1;
                path[len].from = temp;
                q.push(make_pair(make_pair(a,y1-a+x1),len));
            }
        }
        if(x1+y1<=b)
        {
            if(vis[0][x1+y1]==0)
            {
                len ++;
                vis[0][x1+y1] = 1;
                path[len].c ='P';
                path[len].i = 1;
                path[len].j = 2;
                path[len].from = temp;
                q.push(make_pair(make_pair(0,x1+y1),len));
            }
        }
        else
        {
            if(vis[x1+y1-b][b]==0)
            {
                len ++;
                vis[x1+y1-b][b] = 1;
                path[len].c ='P';
                path[len].i = 1;
                path[len].j = 2;
                path[len].from = temp;
                q.push(make_pair(make_pair(x1+y1-b,b),len));
            }
        }
    }
    return -1;
}
void pri(int s)
{
    int len2 = 0;
    int temp =s;
    int num[MAXN];
    num[len2++] = temp;
    while(path[temp].from!=0)///将所有路径上的点的下标记录下来
    {
//        printf("----\n");
        num[len2++] = path[temp].from;
        temp = path[temp].from;
    }
    printf("%d\n",len2);
    for(int i=len2-1;i>=0;i--)
    {
        if(path[num[i]].c=='F')
        {
            printf("FILL(%d)\n",path[num[i]].i);
        }
        else if(path[num[i]].c=='P')
        {
             printf("POUR(%d,%d)\n",path[num[i]].i,path[num[i]].j);
        }
        else if(path[num[i]].c=='D')
        {
            printf("DROP(%d)\n",path[num[i]].i);
        }
    }

}
void init()
{
    len = 0;
    path[len].from = 0;///初始化第一个路径点
    while(!q.empty()) q.pop();
    M(path,0);
    M(vis,0);
}
int main()
{
    while(~scanf("%d %d %d",&a,&b,&c))
    {
        init();
        int ans = bfs(0,0);///初始情况下没有水
        if(ans==-1)
        {
            printf("impossible\n");
        }
        else
        {
            pri(ans);
        }

    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值