题意:
有两个被子,容量分别是A和B,想得到目标容量C(A、B中任意一个容量是C就行)。
有3个操作:
1. FILL(i) fill the pot i (1 ≤ i ≤ 2) from the tap;
2. DROP(i) empty the pot i to the drain;
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).
输出最少步骤,并且回溯操作过程。
题解:
这题是经典的BFS题,难点就是 “回溯操作的过程”。
我是这样做的:我把所有的状态节点从queue pop出来之前,都加到vector里面,保存起来!然后节点cur中有个变量 pre,这个cur.pre表示的是 前一个操作的节点在vector中的下标。其中,节点最多有 100*100=10000个。而状态标记数组可以用f[105][105]来实现。
节点结构:
typedef struct Node{
int x,y,stp,opt,pre;
}Node;
代码:
1A。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
int f[105][105];
typedef struct Node{
int x,y,stp,opt,pre;
}Node;
char s[7][10]={
"","FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"
};
Node st,en;
int A,B,C,ans;
vector<Node >v;
void operate(int indx,Node *nw){
int tot=nw->x+nw->y;
if(indx==1)//fill(1)
nw->x=A;
if(indx==2)//fill(2)
nw->y=B;
if(indx==3)//drop(1)
nw->x=0;
if(indx==4)//drop(2)
nw->y=0;
if(indx==5){//pour(1,2)
if(tot>=B){
nw->x=tot-B;
nw->y=B;
}else{
nw->x=0;
nw->y=tot;
}
}
if(indx==6){//pour(2,1)
if(tot>=A){
nw->x=A;
nw->y=tot-A;
}else{
nw->x=tot;
nw->y=0;
}
}
}
void print_ans(Node en){
if(en.pre==-1){
//printf("%d %s\n",en.stp,s[en.opt]);
return;
}
Node p= v[en.pre];
print_ans(p);
printf("%s\n",s[en.opt]);
}
int main(int argc, const char * argv[]) {
while(~scanf("%d%d%d",&A,&B,&C)){
st.x=0; st.y=0;
st.opt=-1; st.stp=0;
st.pre=-1;
memset(f,0,sizeof(f));
f[0][0]=1;
queue<Node >Q;
v.clear();
Q.push(st);
ans=-1;
while(!Q.empty()){
Node cur,nw;
cur=Q.front();
//节点存档
v.push_back(cur);
if(cur.x==C || cur.y==C) {
ans=cur.stp;
en=cur;
break;
}
for(int i=1;i<=6;i++)
{
nw=cur;
operate(i,&nw);
if(!f[nw.x][nw.y]){
f[nw.x][nw.y]=1;
nw.stp=cur.stp+1;
nw.opt=i;
nw.pre=(int)v.size()-1;
Q.push(nw);
}
}
Q.pop();
}
if(ans!=-1) {
printf("%d\n",ans);
print_ans(en);
}
else puts("impossible");
}
return 0;
}