题目链接:点击打开链接
题意:
有两个壶,分别有A, B升水,问通过三个操作FILL, DROP, POUR,是否能使得这两个壶中有一个壶刚好有C升水。输出最少的操作步数,以及每一步具体的操作。
思路:
bfs,得到最少步数。因为要输出具体步骤,在bfs过程中要记录之前的操作,设置pre指针,指向之前的节点,路径的记录直接用了STL的stack...
在bfs中,我把每一步操作细分,然后用了函数指针数组,方便bfs。
然后dfs,输出路径。
wa了两发,发现忘记输出impossible了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
int a, b, c;
const char str[6][10] = {
"FILL(1)",
"FILL(2)",
"POUR(1,2)",
"POUR(2,1)",
"DROP(1)",
"DROP(2)"
};
struct Node
{
int a, b;
int order, cnt;
Node *pre;
Node(int a, int b, int order, int cnt, Node*pre){
this->a = a; this->b = b; this->order = order;
this->cnt = cnt; this->pre = pre;
}
};
void fill1(Node &tmp){
tmp.a = a;
}
void fill2(Node &tmp){
tmp.b = b;
}
void pour1to2(Node &tmp){
int cha = b - tmp.b;
if(cha < tmp.a){
tmp.b = b;
tmp.a -= cha;
}
else{
tmp.b += tmp.a;
tmp.a = 0;
}
}
void pour2to1(Node &tmp){
int cha = a - tmp.a;
if(cha < tmp.b){
tmp.a = a;
tmp.b -= cha;
}
else{
tmp.a += tmp.b;
tmp.b = 0;
}
}
void drop1(Node &tmp){
tmp.a = 0;
}
void drop2(Node &tmp){
tmp.b = 0;
}
void (*menu[])(Node &tmp) = {fill1, fill2, pour1to2, pour2to1, drop1, drop2};
const int MAXN = 100 + 10;
bool vis[MAXN][MAXN];
void dfs(Node* temp){
if(temp->order==-1 || temp->pre==NULL) return;
dfs(temp->pre);
printf("%s\n", str[temp->order]);
}
void bfs(){
queue<Node> q;
stack<Node> ans;
q.push(Node(0, 0, -1, 0, NULL)); //a, b, order, cnt, pre;
memset(vis, 0, sizeof(vis));
while(!q.empty()){
ans.push(q.front()); q.pop();
Node temp = ans.top();
if(temp.a==c || temp.b==c){
printf("%d\n", temp.cnt);
dfs(&temp);
return;
}
for(int i=0; i<6; ++i){
Node another = temp;
menu[i](another);
if(vis[another.a][another.b]) continue;
another.pre = &ans.top();
another.order = i;
++another.cnt;
q.push(another);
vis[another.a][another.b] = true;
}
}
printf("impossible\n");
}
int main(){
scanf("%d%d%d", &a, &b, &c);
bfs();
return 0;
}