4222. 罐子

给你两个罐子,容积分别为 A 升和 B 升。

现在,你可以进行如下三种操作:

FILL(i),将罐子 i(1≤i≤2)灌满水。
DROP(i),将罐子 i(1≤i≤2)清空。
POUR(i,j),将罐子 i 中的水倒向罐子 j,直到罐子 i 空了或罐子 j 满了为止。
请问,至少多少次操作后,可以使得其中一个罐子里恰好有 C 升水。

输入格式
共一行,三个整数 A,B,C。

输出格式
如果无解,则输出一行 impossible 即可。

否则,第一行输出一个整数,表示最少操作次数。

随后按顺序每行输出一个操作指令,格式参考题面。

数据范围
1≤A,B,C≤100,
C≤max(A,B)。

输入样例:
3 5 4
输出样例:
6
FILL(2)
POUR(2,1)
DROP(1)
POUR(2,1)
FILL(2)
POUR(2,1)

本题难点是找路径,我们通过bfs算法实现,第一次到状态(a,b)则它等于上一个状态+一个操作,并将该状态标记。因为范围小于等于100,所以我们可以开一个string[105][105]数组来进行保存最短路径

#include<iostream>
#include<queue>
using namespace std;
typedef pair<int,int>PII;
typedef pair<PII,int>pii;
int A,B,C;
const int N = 105;
vector<PII>temp,res;
queue<PII>ans;
string op[N][N];
bool dist[N][N];
string st[6]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
int main(){
    scanf("%d%d%d",&A,&B,&C);
    ans.push({0,0});
    dist[0][0]=1;
    while(ans.size()){
        auto it =ans.front();
        int a=it.first,b=it.second;
        ans.pop();
        if(a==C||b==C){
            printf("%d\n",op[a][b].size());
            for(int i(0),l(op[a][b].size());i<l;i++)cout<<st[op[a][b][i]-'0']<<"\n";
            return 0;
        }
        string ts=op[a][b];
        if(!dist[A][b]){ op[A][b] = ts + '0'; dist[A][b] = 1;ans.push({A, b});}
        if(!dist[a][B]){ op[a][B] = ts + '1'; dist[a][B] = 1;ans.push({a, B});}
        if(!dist[0][b]){ op[0][b] = ts + '2'; dist[0][b] = 1;ans.push({0, b});}
        if(!dist[a][0]){ op[a][0] = ts + '3'; dist[a][0] = 1;ans.push({a, 0});}
            {int w = min(a, B - b);
            if(!dist[a - w][b + w]) { op[a - w][b + w] = ts + '4'; dist[a - w][b + w] = 1;ans.push({a - w, b + w});}
           { int w = min(A - a, b);
            if(!dist[a + w][b - w]) { op[a + w][b - w] = ts + '5'; dist[a + w][b - w] = 1;ans.push({a + w, b - w});}
    }
}
    }
cout<<"impossible";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值