POJ3414Pots

转载请注明出处:優YoU http://user.qzone.qq.com/289065406/blog/1303732259

题目大意:

给出了两个瓶子的容量A,B, 以及一个目标水量C

AB可以有如下操作:

FILL(i)        fill the pot i (1 ≤ i ≤ 2) from the tap;

DROP(i)      empty the pot i to the drain;

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).

问经过哪几个操作后能使得任意一个瓶子的残余水量为C

若不可能得到则输出impossible

 

 

 

解题思路:
6
入口的bfs

把两个两个桶的某个同一时间的状态看做一个整体,视为初态

可对初态进行六种操作,即FILL(1),FILL(2),DROP(1),DROP(2),POUR(1,2),POUR(2,1)

6种操作在我的程序中分别用一个整数进行记录;

1z0: 清空z瓶子

2z0: 装满z瓶子

3xy: x瓶倒向y

x,y,z{1,2}

这样在输出操作时就能根据数字的特点 进行选择性输出

 

 

这题有两个难点:

第一就是要输出得到容量C的过程。

对于BFS的题而言这种要求是非常刁钻的,回溯每一步时很容易就混淆了下标。

解决方法:对于每一步的操作,我们都得对它设置一个pos指针,使它指向前一步操作在queue[]队列的下标,即对下标进行回溯,再顺序输出每一步操作

 

第二就是状态记录。怎样记录两个瓶子在同一时间点的状态,又能使得搜索标记时为O(1)的复杂度?

瓶子某时刻的残余水量就是该瓶子的状态,设残余水量为k1 k2

开始时我想对k1 k2进行各种运算组合,但都无法保证k1 k2的运算组合是独一无二的。

最后我决定用 ostringstream k1 k2 两个数字之间加上一个逗号,把他们变为字符串string,再利用map进行标记,相当成功

 

 

最后我简单说说各种操作的数学表达式:

1瓶的容量为v1,残余水量为k1 2瓶的容量为v2,残余水量为 k2

那么 fill(1) 相当于 k1=v1  fill(2)相当于k2=v2  drop(1)相当于k1=0   drop(2)相当于k2=0

对于Pour(1,2),若k1+k2<=v2, k2=k1+k2 k1=0  (有先后顺序)

               否则k1=k1+k2-v2  k2=v2  (有先后顺序)

Pour(2,1)亦同理

 

  1 //Memory Time
2 //232K 32MS
3
4 #include<iostream>
5 #include<string>
6 #include<sstream>
7 #include<map>
8 using namespace std;
9
10 int v1,v2; //两个瓶子的容量
11 int c; //目标残余水量
12
13 int k1,k2; //在某状态时两个瓶子的剩余水量,temporary
14
15 typedef class
16 {
17 public:
18 int x,y; //当前状态(两个瓶子中的水量)
19 int pos; //记录前一状态在队列queue中的下标
20 int step; //当前步数
21 }process;
22
23 //把整数a、b整合为 "a,b" 的字符串形式(不包括引号),用于标记状态
24 string combAB(int a,int b)
25 {
26 string s;
27 ostringstream oss;
28
29 oss<<a;
30 oss<<',';
31 oss<<b;
32
33 s=oss.str();
34 oss.str(""); //清空oss对象内所存储的流
35
36 return s;
37 }
38
39 void fill(int i)
40 {
41 switch(i)
42 {
43 case 1: {k1=v1; return;}
44 case 2: {k2=v2; return;}
45 }
46 }
47
48 void drop(int i)
49 {
50 switch(i)
51 {
52 case 1: {k1=0; return;}
53 case 2: {k2=0; return;}
54 }
55 }
56
57 void pour(int i,int j)
58 {
59 switch(i)
60 {
61 case 1: // v1 to v2
62 {
63 if(k1+k2<=v2)
64 {
65 k2=k1+k2;
66 k1=0;
67 }
68 else
69 {
70 k1=k1+k2-v2;
71 k2=v2;
72 }
73 return;
74 }
75 case 2: // v2 to v1
76 {
77 if(k1+k2<=v1)
78 {
79 k1=k1+k2;
80 k2=0;
81 }
82 else
83 {
84 k2=k1+k2-v1;
85 k1=v1;
86 }
87 return;
88 }
89 }
90 }
91
92 void BFS(void)
93 {
94 int operation[1000]={0}; //当前步的操作: 1z0:清空z瓶子 2z0:装满z瓶子 3xy:从x瓶倒向y瓶
95
96 map<string,bool>vist;
97 vist["0,0"]=true;
98
99 process queue[1000]; //状态队列
100 int head,tail;
101 queue[head=0].x=0;
102 queue[tail=0].y=0;
103 queue[tail++].step=0;
104
105 string ts; //temporary
106 while(head<tail)
107 {
108 process p=queue[head];
109
110 if(p.x==c || p.y==c) //得到要求的剩余水量c
111 {
112 cout<<p.step<<endl;
113
114 /*下标回溯,输出操作过程*/
115
116 int ps=p.step;
117 int* steps=new int[ps+1]; //从1到p.step顺序记录各步操作的下标,不使用steps[0]
118
119 steps[ps--]=tail-1;
120 while(ps)
121 {
122 steps[ps]=queue[ steps[ps+1] ].pos;
123 ps--;
124 }
125
126 for(int i=1;i<=p.step;i++)
127 {
128 int temp=operation[ steps[i]-1 ]; //注意各个数组间的下标关系
129
130 switch(temp/100)
131 {
132 case 1:
133 {
134 cout<<"DROP("<<(temp/10)%10<<')'<<endl;
135 break;
136 }
137 case 2:
138 {
139 cout<<"FILL("<<(temp/10)%10<<')'<<endl;
140 break;
141 }
142 case 3:
143 {
144 cout<<"POUR("<<(temp/10)%10<<','<<temp%10<<')'<<endl;
145 break;
146 }
147 }
148 }
149
150 delete steps;
151
152 return;
153 }
154
155 /*装满v1*/
156
157 k1=p.x;
158 k2=p.y;
159 fill(1);
160 ts=combAB(k1,k2);
161 if(!vist[ts])
162 {
163 vist[ts]=true;
164 queue[tail].x=k1;
165 queue[tail].y=k2;
166 queue[tail].step=p.step+1; //当前的操作步数
167 queue[tail].pos=head; //前一步操作在queue[]中的下标
168 operation[tail++]=210; //当前的操作
169 }
170
171 /*装满v2*/
172
173 k1=p.x;
174 k2=p.y;
175 fill(2);
176 ts=combAB(k1,k2);
177 if(!vist[ts])
178 {
179 vist[ts]=true;
180 queue[tail].x=k1;
181 queue[tail].y=k2;
182 queue[tail].step=p.step+1;
183 queue[tail].pos=head;
184 operation[tail++]=220;
185 }
186
187 /*清空v1*/
188
189 k1=p.x;
190 k2=p.y;
191 drop(1);
192 ts=combAB(k1,k2);
193 if(!vist[ts])
194 {
195 vist[ts]=true;
196 queue[tail].x=k1;
197 queue[tail].y=k2;
198 queue[tail].step=p.step+1;
199 queue[tail].pos=head;
200 operation[tail++]=110;
201 }
202
203 /*清空v2*/
204
205 k1=p.x;
206 k2=p.y;
207 drop(2);
208 ts=combAB(k1,k2);
209 if(!vist[ts])
210 {
211 vist[ts]=true;
212 queue[tail].x=k1;
213 queue[tail].y=k2;
214 queue[tail].step=p.step+1;
215 queue[tail].pos=head;
216 operation[tail++]=120;
217 }
218
219 /*v1倒向v2*/
220
221 k1=p.x;
222 k2=p.y;
223 pour(1,2);
224 ts=combAB(k1,k2);
225 if(!vist[ts])
226 {
227 vist[ts]=true;
228 queue[tail].x=k1;
229 queue[tail].y=k2;
230 queue[tail].step=p.step+1;
231 queue[tail].pos=head;
232 operation[tail++]=312;
233 }
234
235 /*v2倒向v1*/
236
237 k1=p.x;
238 k2=p.y;
239 pour(2,1);
240 ts=combAB(k1,k2);
241 if(!vist[ts])
242 {
243 vist[ts]=true;
244 queue[tail].x=k1;
245 queue[tail].y=k2;
246 queue[tail].step=p.step+1;
247 queue[tail].pos=head;
248 operation[tail++]=321;
249 }
250
251 head++;
252 }
253
254 cout<<"impossible"<<endl;
255 return;
256 }
257
258 int main(void)
259 {
260 while(cin>>v1>>v2>>c)
261 BFS();
262 return 0;
263 }
原文地址:https://www.cnblogs.com/lyy289065406/p/2122527.html