POJ 3134 Power Calculus ★(记录状态的BFS)

题目大意:给定初始的x,可以通过乘法将其变为x^2,再变为x^4,x^8,x^16,x^32,也可以用除法,x^31 = x^32 / x,但是操作数必须是已经计算出来的数,给定一个指数,要求得到这个指数的最小步数。比如31输出6(1 2 4 8 16 32 31).   想错了很多次……求最优路径问题嘛,就是ID-DFS or BFS。事实证明两种方法确实都可以。一般 当时间宽裕空间紧张时选ID-DFS;当时间紧而空间宽裕时选BFS。可是因为我的姿势丑……BFS加了各种优化才勉强2s过,ID-DFS显然各种吃紧了……囧。   回到题目。首先一个直观的想法就是BFS,并且因为我们每次扩展状态时都要依据前面过程中的数,所以需要用一个数组记录下来当前状态的前面的状态。这样我们BFS队列里存的就是一个结构体,包括当前状态的指数,当前步数,和存与当前状态相关的前面状态的数组。然后为了减少状态要去重,队列中只保存得到某个数花费步数最短的一种状态。 但是结果953怎么算都是13……跑到Discuss里看了下结果:(1 2 4 8 7 15 30 60 120 240 480 473 953),然后我们对473做一次BFS打印一下结果:(1 2 4 8 16 32 31 63 126 252 504 473)。于是我们发现了问题所在:得到某个数花费最少步数的状态可能不同,而不同的状态对后面数的影响是不同的,所以我们需要把某数步数相同且最短的状态都存起来。 (但我还有一个疑问是为什么步数更长的状态不会使后面有更好的结果……囧……反正数据没出现这种情况……) 但是因为我的姿势丑……T_T……这样还是TLE……看了一位大牛的博客又加了一个优化:限制某个数的状态在队列中只能出现limit次(我设的10),虽然确实通过了……但是还是不会证明正确性……T_T……   PS:为什么我的姿势这么丑……T^T……  
#include 
 
   
    
  
#include 
  
    
      #include 
     
       #include 
      
        using namespace std; struct Queue{ int num, time; int pre[20], pre_num; }; queue 
       
         Q; int qnum,it; int step[2110]; int cnt[2110]; int BFS(int n){ for (int i = 0; i < 2110; i ++){ step[i] = 1 << 30; cnt[i] = 0; } while(!Q.empty()) Q.pop(); Queue tmp; tmp.num = 1; tmp.time = 0; tmp.pre_num = 0; tmp.pre[tmp.pre_num ++] = 1; Q.push(tmp); step[1] = 1; while(!Q.empty()){ Queue tmp = Q.front(); if (tmp.num == n){ // int p = it; // while(p != 0){ // p = Q[p].pre; // cout << Q[p].num << endl; // } return tmp.time; } step[tmp.num] = tmp.time; for (int i = 0; i < tmp.pre_num; i ++){ for (int j = -1; j <= 1; j += 2){ Queue p = tmp; p.num = p.num + p.pre[i] * j; p.time ++; if (p.num > 1 && p.num <= 2000){ if(step[p.num] > p.time){ step[p.num] = p.time; cnt[p.num] = 1; p.pre[p.pre_num ++] = p.num; Q.push(p); } else if (step[p.num] == p.time){ if (cnt[p.num] <= 10){ p.pre[p.pre_num ++] = p.num; Q.push(p); cnt[p.num] ++; } } } } } Q.pop(); } } int main(){ int n; while(cin >> n, n){ cout << BFS(n) << endl; } return 0; } 
        
       
      
    
 
   
 

你可能感兴趣的:(poj)