题意:
给出两个水壶的容量A,B, 和一个目标水壶容量C,
对水壶可以有三种操作:
1、FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap;
把水壶(1或2)装满
2、DROP(i) empty the pot i to the drain;
把水壶(1或2)全部倒了
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).
把水壶 i 的水全部倒倒 水壶 j 中
问:
如果经过几个操作可以使任意一个瓶子的残余水量为C,则输出多少个操作,哪几个操作
如果不可能得到残余水量为C,则输出impossible
解题思路:
问题1:搜索什么时候应该停止
A,B,C的取值范围是1~100,因此可以使用一个二维数组来表示水壶的状态
map[ i ][ j ]: 表示水壶1有 i 升水,水壶2有 j 升水的状态,根据题意有(A+1)*(B+1)种状态, 最多10201种状态。
当(A+1)*(B+1)种状态都搜索过或搜索到目标容量C状态时,搜索应该停止
从当前状态map[ i ][ j ]出发一共有6种方法:
方法1:装满水壶1 转移状态到map[ A ][ j ]
方法2:倒空水壶1 转移状态到map[ 0 ][ j ]
方法3:水壶1的水倒入水壶2
方法4:装满水壶2 转移状态到map[ i ][ B ]
方法5:倒空水壶2 转移状态到map[ i ][ 0 ]
方法6:水壶2的水倒入水壶1
问题2:如何回溯
map[ i ][ j ]: 表示水壶1有 i 升水,水壶2有 j 升水的状态。在这个二维数组中,需要存储4个信息:表示前一个状态时两个水壶装了多少水,前一个状态到当前状态时采用了哪种方法(数字表示,对应前面的6种方法的排序),到当前状态一共执行了几步操作。
typedef struct
{
int prefirst;//表示前一个状态时,水壶1装了多少水
int presecond;//表示前一个状态时,水壶2装了多少水
int preOper;//前一个状态到当前状态时采用了哪种方法(数字表示,对应前面的6种方法)
int steps;//到当前状态一共执行了几步操作。-1表示没有搜索过。
}node;
node map[110][110];
搜索到 水壶1或水壶2为C时,记录当前状态,开始回溯,操作被逆序存放在recordOper数组种
void backSteps(int x, int y)
{
int i=0;
int preX, preY;
while(x!=0 || y!=0)
{
recordOper[i] = map[x][y].preOper;
preX = map[x][y].prefirst;
preY = map[x][y].presecond;
x = preX;
y = preY;
i++;
}
}
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int A, B, C;
int recordOper[10000];
typedef struct
{
int first;//水壶1装了多少水
int second;//水壶2装了多少水
}pos;
typedef struct
{
int prefirst;//表示前一个状态时,水壶1装了多少水
int presecond;//表示前一个状态时,水壶2装了多少水
int preOper;//前一个状态到当前状态时采用了哪种方法(数字表示,对应前面的6种方法)
int steps;//到当前状态一共执行了几步操作。-1表示没有搜索过。
}node;
node map[110][110];
void operation(int op, pos &next, pos &tmp)
{
if(op == 1)//FILL(第一个) fill the pot i (1 ≤ i ≤ 2) from the tap;
{
next.first = A;
next.second = tmp.second;
}
if(op == 2)//DROP(第一个) empty the pot i to the drain;
{
next.first = 0;
next.second = tmp.second;
}
if(op == 3)//POUR(1,2) 把第一个往第二个倒,需要判断水壶2的水会不会满
{
if(tmp.first+tmp.second >= B)
{
next. first = tmp.first+tmp.second - B;
next.second = B;
}
else
{
next.first = 0;
next.second = tmp.first+tmp.second;
}
}
if(op == 4)//FILL(第二个) fill the pot i (1 ≤ i ≤ 2) from the tap;
{
next.first = tmp.first;
next.second = B;
}
if(op == 5)//DROP(第二个) empty the pot i to the drain;
{
next.first = tmp.first;;
next.second = 0;
}
if(op ==6)//POUR(2,1) 把第二个往第一个倒,需要判断水壶1的水会不会满
{
if(tmp.first+tmp.second >= A)
{
next.first = A;
next.second = tmp.first+tmp.second - A;
}
else
{
next.first = tmp.first+tmp.second;
next.second = 0;
}
}
}
void backSteps(int x, int y)
{
int i=0;
int preX, preY;
while(x!=0 || y!=0)
{
recordOper[i] = map[x][y].preOper;
preX = map[x][y].prefirst;
preY = map[x][y].presecond;
x = preX;
y = preY;
i++;
}
}
int dfs()
{
int ret = -1;
pos tmp,next;
queue<pos> q;
q.push(pos{0,0});
while(q.size())
{
tmp = q.front();
q.pop();
if(tmp.first==C || tmp.second==C)//
{
ret = map[tmp.first][tmp.second].steps;
backSteps(tmp.first, tmp.second);
break;
}
for (int i = 1; i < 7; ++i)
{
operation(i, next, tmp);
if(map[next.first][next.second].steps == -1)
{
map[next.first][next.second].prefirst = tmp.first;
map[next.first][next.second].presecond = tmp.second;
map[next.first][next.second].preOper = i;
map[next.first][next.second].steps = map[tmp.first][tmp.second].steps + 1;
q.push(next);
}
}
}
while(q.size())
q.pop();
return ret;
}
int main()
{
int ans;
while(~scanf("%d %d %d", &A, &B, &C))
{
for(int i = 0; i <= A; i++)
{
for(int j = 0; j <= B; j++)
{
map[i][j].steps = -1;
}
}
map[0][0].steps = 0;//忘了初始化,贡献了一发WA
ans = dfs();//ans是操作数,如果ans=-1,说明时不可能的。
if(ans == -1)
printf("impossible\n");
else
{ //如果ans不等于-1,说明可行,并且具体操作被逆序存放在recordOper
printf("%d\n", ans);
for(int i = ans-1; i>=0; i--)
{
if(recordOper[i] == 1)
printf("FILL(1)\n");
if(recordOper[i] == 2)
printf("DROP(1)\n");
if(recordOper[i] == 3)
printf("POUR(1,2)\n");
if(recordOper[i] == 4)
printf("FILL(2)\n");
if(recordOper[i] == 5)
printf("DROP(2)\n");
if(recordOper[i] == 6)
printf("POUR(2,1)\n");
}
}
}
return 0;
}
注:有觉得解释不清的地方,可以留言,我再继续改进一下