题解 P1432 【倒水问题】
zhaotiensn · · 题解
(竟然发这题题解的人那么少,那么我就来水一发题解)
解题思路:
宽搜BFS一看就是要以最少的次数到达题目的要求,想到最少就想到了宽搜 BFS,还是比较裸的BFS,相对比较简单。
本人的BFS:通过普通的队列来进行搜索,建立一个vis数组来储存这种情况是否出现过,然后向6个方向拓展(fill A,fill B, empty A, empty B ,pour A B,pour B A),遇到新的点就放入队尾。然后将队首的点出队进行搜索,当搜索到的点符合题目要求就返回答案。
接下来贴代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,a,b,c,l,r;//a,b,c就是题中的变量,l为队首指针,r为队尾指针。
int ai[10000],bi[10000],ans[10000],f[10000][10000];//ai,bi分别为A,B中的水,f数组储存到达当前情况进行的操作,ans为当前情况进行的操作总数。
bool vis[2000][2000];//vis用来是否搜索过。
void bfs(int x,int y) {
if(y==c) { //当B中的水与需要的C相等时开始输出
cout<<ans[l]<<" ";
for(int i=1; i<=ans[l]; i++) { //输出进行的操作
cout<<f[l][i]<<" ";
}
cout<<endl;//成功
return;
}
for(int i=1; i<=6; i++) { //对6个方向进行拓展
if((i==1)&&(x!=a)&&(!vis[a][y])) { //当搜索过了或者A本来就是满的,fill A为无效的
++r;//队尾指针+1。
ai[r]=a;//进行 fill A 操作后入队
bi[r]=y;
vis[a][y]=true;//标记
ans[r]=ans[l]+1;
for(int j=1; j<=ans[l]; j++)f[r][j]=f[l][j];
f[r][ans[r]]=i;//将之前的操作赋值给新的状况
}
if((i==2)&&(y!=b)&&(!vis[x][b])) { //同上
++r;
ai[r]=x;//同上
bi[r]=b;
vis[x][b]=true;
ans[r]=ans[l]+1;
for(int j=1; j<=ans[l]; j++)f[r][j]=f[l][j];
f[r][ans[r]]=i;//同上
}
if((i==3)&&(x!=0)&&(!vis[0][y])) { //同上,当A本为空或已搜索都是无效操作
++r;
ai[r]=0;//同上
bi[r]=y;
ans[r]=ans[l]+1;
vis[x][b]=true;
for(int j=1; j<=ans[l]; j++)f[r][j]=f[l][j];
f[r][ans[r]]=i;//同上
}
if((i==4)&&(y!=0)&&(!vis[x][0])) { //同上
++r;
ai[r]=x;
bi[r]=0;
ans[r]=ans[l]+1;
vis[x][b]=true;
for(int j=1; j<=ans[l]; j++)f[r][j]=f[l][j];
f[r][ans[r]]=i;
}
if((i==5)&&(x!=a)&&(y!=0)&&(!vis[x+y][0])) {
++r;//当A为满或B为空,都是无效操作。
vis[x+y][0]=true;//直接用x+y代替的比用直接用x,y做下标好,可以省代码,而且如A为6,B为4或A为9,b为1可以看做操作后是同一种情况。
if(x+y<=a) { //如果A装不满的情况
ai[r]=x+y;
bi[r]=0;
} else { //如果A装满了的情况
ai[r]=a;
bi[r]=x+y-a;
}
ans[r]=ans[l]+1;
for(int j=1; j<=ans[l]; j++)f[r][j]=f[l][j];
f[r][ans[r]]=i;
}
if((i==6)&&(x!=0)&&(y!=b)&&(!vis[0][x+y])) {
++r;//同上
vis[0][x+y]=true;
if(x+y<=b) {
ai[r]=0;
bi[r]=x+y;
} else { //同上
ai[r]=x+y-b;
bi[r]=b;
}
ans[r]=ans[l]+1;
for(int j=1; j<=ans[l]; j++)f[r][j]=f[l][j];
f[r][ans[r]]=i;
}
}
++l;//队首指针+1,队首出队
if(l<=r)bfs(ai[l],bi[l]);
else return;
return;//对它进行拓展,如果l>r,即没有未搜索过的点则说明这种情况无解
}
int main() {
cin>>n;
while(n--) {
cin>>a>>b>>c;
l=0;
r=0;//初始化
memset(vis,false,2000*2000);//也是初始化
bfs(0,0);//从两个壶都没有水开始搜索
}
return 0;
}