PKU1945 Power Hungry Cows

【题目大意】

开始时有两个变量(A=x^a,B=x^b),每次可以做以下爱几种运算:

A*BA*AB*BA/BB/AA/AB/B

并把结果放到某个变量中,问最少多少步可以得到目标X^P

【题目分析】

我们可以只记录当前两个变量的指数,这样各种操作就变成了加和减,可以直接进行BFS,但是显然会超时,于是我们先从状态入手,规定a<=b,这样就把状态数减少了一半,而操作中的除法也就只剩下b/a这一种情况了,再继续考虑优化。

对于各种操作,其实A*A这个变化时与一些操作重复的,所以可以去掉这个变换,这样就减少了搜索树结点的度,使能达到的节点数更少了。

状态树上已经不能再优化了,继续考虑较少扩展量,有如下两个剪枝

①如果p mod gcd(A,B)<>0 那么状态<A,B>一定必能出解

②如果A>=100B>=50000那么该状态无解

以上两个剪枝笔者都不会证明。。。。

以上两个剪枝加入后程序性能有所改善,但是仍然不能在时间限制内出解。我们只能考虑搜索扩展规则上的优化,使用A*算法。

 

介绍一下A*算法,给每一个状态一个估价值,表示该状态达到目标的期望水平,函数值越大,则该节点越有可能达到解,因此,我们在进行A*算法时需要维护两个表,表一代替了朴素BFS中的队列,能够在较短时间内取出并删除函数值最大的结点,还能在较短时间内插入新节点,而第二个表则是用来判重的,能够支持插入节点和查询节点是否已经存在,对于数据结构了解比较清楚的同学可能已经知道他们应该用什么实现了,表一用一个二叉堆来实现,在logn时间内完成插入操作或取出最小值并维护形态,表二则用一个平衡树或hash表来实现,个人推荐平衡树,比较稳定,不会像hash那样出问题。这样,A*的数据结构就选好了。

接下来确定的是估价函数,最快情况下变量按2的指数级别增长,所以定义H(state)为变量B不断自乘2最少多少次能大于等于P,定义G(state)为该节点的深度,定义估价函数F(state)=G(state)*2+H(state)

这里给G(state)2是为了保证估价函数的相容性,即保证先扩展出来的结点的步数一定是最优的,这样才能得到最优解。同时,利用刚刚的朴素BFS程序,我们还可以得到数据范围内的最大步数大概在20左右,所以如果某结点函数F(state)>20*2,那么我们完全可以舍弃这个节点。

如果还是不能出解,我们就要考虑牺牲解的正确性了,我的做法是在数据较强时估价函数G不乘2,这样时间大幅下降。

这样加入所有的优化后,程序效率明显上升,能够在较短时间内出解。而且结点总数在20万以下,可以说已经优化的很好了。

 

View Code
  1 {$inline on}
  2 program usaco_power(input,output);
  3 const
  4     maxpower= 200000;
  5 type
  6     nodes=record
  7         x,y:longint;
  8     end;
  9     size_balance_tree=object
 10         root,tot:longint;
 11         s,left,right:array[0..200000] of longint;
 12         key:array[0..300000] of nodes;
 13         procedure clean;
 14         procedure left_rotate(var t:longint);
 15         procedure right_rotate(var t:longint);
 16         procedure maintain(var t:longint;flag:boolean);
 17         procedure insert(var t:longint;xx:nodes);
 18         function find(t:longint;xx:nodes):boolean;
 19     end;
 20     node=record
 21         x,y,w,step:longint;
 22     end;
 23     Theap=object
 24         tot:longint;
 25         list:array[0..100000] of node;
 26         procedure clean;
 27         procedure swap(var aa,bb:longint);
 28         procedure up(now:longint);
 29         procedure down(now:longint);
 30         procedure insert(now:node);
 31         function delete():node;
 32     end;
 33 procedure size_balance_tree.clean(); 
 34 begin
 35     root:=0;
 36     tot:=0;
 37     fillchar(left,sizeof(left),0);
 38     fillchar(right,sizeof(right),0);
 39     fillchar(s,sizeof(s),0);
 40     fillchar(key,sizeof(key),0);
 41 end;
 42 procedure size_balance_tree.left_rotate(var t:longint); 
 43 var
 44     k:longint;
 45 begin
 46     k:=right[t];
 47     right[t]:=left[k];
 48     left[k]:=t;
 49     s[k]:=s[t];
 50     s[t]:=s[left[t]]+s[right[t]]+1;
 51     t:=k;
 52 end;
 53 procedure size_balance_tree.right_rotate(var t:longint); 
 54 var
 55     k:longint;
 56 begin
 57     k:=left[t];
 58     left[t]:=right[k];
 59     right[k]:=t;
 60     s[k]:=s[t];
 61     s[t]:=s[left[t]]+s[right[t]]+1;
 62     t:=k;
 63 end;
 64 procedure size_balance_tree.maintain(var t:longint;flag:boolean);
 65 begin
 66     if not flag then
 67     begin
 68         if s[left[left[t]]]>s[right[t]] then
 69             size_balance_tree.right_rotate(t)
 70         else
 71             if s[right[left[t]]]>s[right[t]] then
 72             begin
 73                 size_balance_tree.left_rotate(left[t]);
 74                 size_balance_tree.right_rotate(t);
 75             end
 76             else
 77                 exit;
 78     end
 79     else
 80     begin
 81         if s[right[right[t]]]>s[left[t]] then
 82             size_balance_tree.left_rotate(t)
 83         else
 84             if s[left[right[t]]]>s[left[t]] then
 85             begin
 86                 size_balance_tree.right_rotate(right[t]);
 87                 size_balance_tree.left_rotate(t);
 88             end
 89             else
 90                 exit;
 91     end;
 92     size_balance_tree.maintain(left[t],false);
 93     size_balance_tree.maintain(right[t],true);
 94     size_balance_tree.maintain(t,false);
 95     size_balance_tree.maintain(t,true);
 96 end;
 97 procedure size_balance_tree.insert(var t:longint;xx:nodes); 
 98 begin
 99     if t=0 then
100     begin
101         inc(tot);
102         t:=tot;
103         left[t]:=0;
104         right[t]:=0;
105         s[t]:=1;
106         key[t]:=xx;
107     end
108     else
109     begin
110         inc(s[t]);
111         if (xx.x*maxpower+xx.y)<(key[t].x*maxpower+key[t].y) then
112             size_balance_tree.insert(left[t],xx)
113         else
114             size_balance_tree.insert(right[t],xx);
115         size_balance_tree.maintain(t,xx.x*maxpower+xx.y>=key[t].x*maxpower+key[t].y);
116     end;
117 end;
118 function size_balance_tree.find(t:longint;xx:nodes):boolean; 
119 begin
120     if t=0 then
121         exit(false);
122     if (key[t].x=xx.x)and(key[t].y=xx.y) then
123         exit(true);
124     if (xx.x*maxpower+xx.y)<(key[t].x*maxpower+key[t].y) then
125         exit(size_balance_tree.find(left[t],xx))
126     else
127         exit(size_balance_tree.find(right[t],xx));
128 end;
129 
130 
131 procedure Theap.clean(); 
132 begin
133     fillchar(list,sizeof(list),0);
134     tot:=0;
135 end;
136 procedure Theap.swap(var aa,bb:longint); 
137 var
138     tt:longint;
139 begin
140     tt:=aa;
141     aa:=bb;
142     bb:=tt;
143 end;
144 procedure Theap.up(now:longint); 
145 begin
146     while (now>1)and(list[now].w<list[now>>1].w) do
147     begin
148         Theap.swap(list[now].x,list[now>>1].x);
149         Theap.swap(list[now].y,list[now>>1].y);
150         Theap.swap(list[now].w,list[now>>1].w);
151         Theap.swap(list[now].step,list[now>>1].step);
152         now:=now>>1;
153     end;
154 end;
155 procedure Theap.down(now:longint); 
156 var
157     tmp:longint;
158 begin
159     while (now*2<=tot) do
160     begin
161         tmp:=now*2;
162         if (tmp+1<=tot)and(list[tmp+1].w<list[tmp].w) then
163             inc(tmp);
164         if list[tmp].w<list[now].w then
165         begin
166             Theap.swap(list[now].x,list[tmp].x);
167             Theap.swap(list[now].y,list[tmp].y);
168             Theap.swap(list[now].w,list[tmp].w);
169             Theap.swap(list[now].step,list[tmp].step);
170             now:=tmp;
171         end
172         else
173             break;
174     end;
175 end;
176 procedure Theap.insert(now:node); 
177 begin
178     inc(tot);
179     list[tot]:=now;
180     Theap.up(tot);
181 end;
182 function Theap.delete():node; 
183 begin
184     delete:=list[1];
185     Theap.swap(list[1].x,list[tot].x);
186     Theap.swap(list[1].y,list[tot].y);
187     Theap.swap(list[1].w,list[tot].w);
188     Theap.swap(list[1].step,list[tot].step);    
189     dec(tot);
190     Theap.down(1);
191 end;
192 
193 var
194     tree:size_balance_tree;
195     heap:Theap;
196     goal,answer:longint;
197     answer_flag,check_goal:boolean;
198 function gcd(a,b:longint):longint; inline;
199 begin
200     if b=0 then
201         exit(a);
202     exit(gcd(b,a mod b));
203 end;{ gcd }
204 procedure check();
205 var
206     i,s:longint;
207 begin;
208     s:=0;
209     for i:=0 to 30 do
210         if ((1<<i) and goal)>0 then
211             inc(s);
212     if s<=9 then
213         check_goal:=true
214     else
215         check_goal:=false;
216 end;
217 function f(now:node):longint; inline;
218 var
219     tmp:longint;
220 begin
221     f:=0;
222     tmp:=now.y;
223     if tmp=0 then
224         exit(maxlongint>>1);
225     while tmp<goal do
226     begin
227         tmp:=tmp+tmp;
228         inc(f);
229     end;
230     if (check_goal)and(goal>10000) then
231         f:=f+now.step
232     else
233         f:=f+now.step<<1;
234 end;{ f }
235 procedure swap(var aa,bb:longint); inline;
236 var
237     tt:longint;
238 begin
239     tt:=aa;
240     aa:=bb;
241     bb:=tt;
242 end;{ swap }
243 procedure init; inline;
244 var
245     now:node;
246     new:nodes;
247 begin
248     readln(goal);
249     check();
250     tree.clean();
251     heap.clean();
252     now.x:=0;
253     now.y:=1;
254     now.step:=0;
255     now.w:=f(now);
256     new.x:=0;
257     new.y:=1;
258     tree.insert(tree.root,new);
259     heap.insert(now);
260 end;{ init }
261 function operand(now:node;flag:longint):node; inline;
262 begin
263     case flag of
264         1:begin
265             operand.x:=now.x;
266             operand.y:=now.x+now.y;
267             operand.step:=now.step+1;
268         end;
269         2:begin
270             operand.x:=now.x+now.y;
271             operand.y:=now.y;
272             operand.step:=now.step+1;
273         end;
274         3:begin
275             operand.x:=now.y-now.x;
276             operand.y:=now.y;
277             operand.step:=now.step+1;
278         end;
279         4:begin
280             operand.x:=now.x;
281             operand.y:=now.y-now.x;
282             operand.step:=now.step+1;
283         end;
284         {5:begin
285             operand.x:=now.x+now.x;
286             operand.y:=now.y;
287             operand.step:=now.step+1;
288         end;
289         6:begin
290             operand.x:=now.x;
291             operand.y:=now.x+now.x;
292             operand.step:=now.step+1;
293         end;}
294         5:begin
295             operand.x:=now.y+now.y;
296             operand.y:=now.y;
297             operand.step:=now.step+1;
298         end;
299         6:begin
300             operand.x:=now.x;
301             operand.y:=now.y+now.y;
302             operand.step:=now.step+1;
303         end;
304     end;
305     if operand.y<operand.x then
306         swap(operand.x,operand.y);
307 end;{ operand }
308 procedure expand(now:node); inline;
309 var
310     newstate:node;
311     pd:nodes;
312     i:longint;
313 begin
314     for i:=1 to 6 do
315     begin
316         newstate:=operand(now,i);
317         if not ((newstate.x<=100)and(newstate.y<=50000)) then
318             continue;
319         if newstate.y=0 then
320             continue;
321         if (goal mod gcd(newstate.x,newstate.y))<>0 then
322             continue;
323         if (newstate.x=goal)or(newstate.y=goal) then
324         begin
325             answer_flag:=true;
326             answer:=newstate.step;
327             exit;
328         end;
329         newstate.w:=f(newstate);
330         if newstate.w>40 then
331             continue;
332         pd.x:=newstate.x;
333         pd.y:=newstate.y;
334         if tree.find(tree.root,pd) then
335             continue;
336         tree.insert(tree.root,pd);
337         heap.insert(newstate);
338     end;
339 end;{ expand }
340 procedure A_star; inline;
341 var
342     state:node;
343 begin
344     answer_flag:=false;
345     while heap.tot<>0 do
346     begin
347         state:=heap.delete();
348         expand(state);
349         if answer_flag then
350             break;
351     end;
352 end;{ A_star }
353 procedure print; inline;
354 begin
355     writeln(answer);
356 end;{ print }
357 begin
358     init;
359     A_star;
360     print;
361 end.

 

 

 

posted @ 2012-10-10 19:35  Codinginging  阅读(1584)  评论(0编辑  收藏  举报