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

     

     

  • 相关阅读:
    无线传感器网络 与 OMNET++学习笔记(二) NED
    无线传感器网络 与 OMNET++学习笔记(一)
    win10:未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序
    XML 命名空间“clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit”中不存在标记“Chart”
    白书动态规划例题和习题简解
    BZOJ 1266
    BZOJ 1001 (UVa1376, LA3661 )
    UVa 11178
    BZOJ 1787 裸LCA
    BZOJ 2440
  • 原文地址:https://www.cnblogs.com/neverforget/p/2718778.html
Copyright © 2020-2023  润新知