题意
有容积为A,B两个容器,有三种操作:FILL:充满其中的一个容器;DROP:将其中一个容器清空;POUR:将一个容器倒入另一个容器,直至充满。两个容器重复这些操作,能不能得到容积为C,输出具体的操作过程。
思路
这是一道bfs题,主要是记录操作的过程有技巧性。
代码
#include <stdio.h>
#include <cstring>
enum ACTION {
NONE=0,
FILL_1,
FILL_2,
DROP_1,
DROP_2,
POUR_12,
POUR_21,
END
};
struct NODE {
int a;
int b;
int dis;
int pre;
ACTION action;
}edge[10001];
int visited[101][101];
int front = 0, rear = 1;
int A, B, C;
bool checkNode(NODE node) {
if (node.a == C || node.b == C)
return true;
return false;
}
void print(int i) {
if (edge[i].pre != -1) {
print(edge[i].pre);
switch (edge[i].action) {
case FILL_1:
printf("FILL(1)\n");
break;
case FILL_2:
printf("FILL(2)\n");
break;
case DROP_1:
printf("DROP(1)\n");
break;
case DROP_2:
printf("DROP(2)\n");
break;
case POUR_12:
printf("POUR(1,2)\n");
break;
case POUR_21:
printf("POUR(2,1)\n");
break;
default:
break;
}
}
}
void bfs() {
edge[front].a = 0;
edge[front].b = 0;
edge[front].dis = 0;
edge[front].pre = -1;
edge[front].action = NONE;
while (front<rear){
for (int i = FILL_1; i < END;i++) {
int na, nb, k;
switch (i) {
case FILL_1:
na = A;
nb = edge[front].b;
if (edge[front].a < A && !visited[na][nb]) {
visited[na][nb] = 1;
edge[rear].a = na;
edge[rear].b = nb;
edge[rear].dis = edge[front].dis + 1;
edge[rear].pre = front;
edge[rear].action = FILL_1;
if (checkNode(edge[rear])) {
printf("%d\n", edge[rear].dis);
print(rear);
return;
}
rear++;
}
break;
case FILL_2:
na = edge[front].a;
nb = B;
if (edge[front].b < B && !visited[na][nb]) {
visited[na][nb] = 1;
edge[rear].a = na;
edge[rear].b = nb;
edge[rear].dis = edge[front].dis + 1;
edge[rear].pre = front;
edge[rear].action = FILL_2;
if (checkNode(edge[rear])) {
printf("%d\n", edge[rear].dis);
print(rear);
return;
}
rear++;
}
break;
case DROP_1:
na = 0;
nb = edge[front].b;
if (edge[front].a > 0 && !visited[na][nb]) {
visited[na][nb] = 1;
edge[rear].a = 0;
edge[rear].b = nb;
edge[rear].dis = edge[front].dis + 1;
edge[rear].pre = front;
edge[rear].action = DROP_1;
if (checkNode(edge[rear])) {
printf("%d\n", edge[rear].dis);
print(rear);
return;
}
rear++;
}
break;
case DROP_2:
na = edge[front].a;
nb = 0;
if (edge[front].b > 0 && !visited[na][nb]) {
visited[na][nb] = 1;
edge[rear].a = na;
edge[rear].b = nb;
edge[rear].dis = edge[front].dis + 1;
edge[rear].pre = front;
edge[rear].action = DROP_2;
if (checkNode(edge[rear])) {
printf("%d\n", edge[rear].dis);
print(rear);
return;
}
rear++;
}
break;
case POUR_12:
if (edge[front].a == 0 || edge[front].b==B)
break;
k = edge[front].a - (B - edge[front].b);
if (k > 0) {
na = k;
nb = B;
}else {
na = 0;
nb = edge[front].a + edge[front].b;
}
if (!visited[na][nb]) {
visited[na][nb] = 1;
edge[rear].a = na;
edge[rear].b = nb;
edge[rear].dis = edge[front].dis + 1;
edge[rear].pre = front;
edge[rear].action = POUR_12;
if (checkNode(edge[rear])) {
printf("%d\n", edge[rear].dis);
print(rear);
return;
}
rear++;
}
break;
case POUR_21:
if (edge[front].a == A || edge[front].b == 0)
break;
k = edge[front].b - (A - edge[front].a);
if (k > 0) {
na = A;
nb = k;
}
else {
na = edge[front].a + edge[front].b;
nb = 0;
}
if (!visited[na][nb]) {
visited[na][nb] = 1;
edge[rear].a = na;
edge[rear].b = nb;
edge[rear].dis = edge[front].dis + 1;
edge[rear].pre = front;
edge[rear].action = POUR_21;
if (checkNode(edge[rear])) {
printf("%d\n", edge[rear].dis);
print(rear);
return;
}
rear++;
}
break;
default:
break;
}
}
front++;
}
printf("impossible\n");
}
int main() {
while (~scanf("%d%d%d",&A,&B,&C)) {
memset(edge, 0, sizeof(edge));
memset(visited, 0, sizeof(visited));
bfs();
}
return 0;
}