给你两个罐子,容积分别为 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";
}