您的位置:首页 > 其它

UVa 1374 - Power Calculus——[迭代加深搜索、快速幂]

2016-04-01 21:26 417 查看

解题思路:

  这是一道以快速幂计算为原理的题,实际上也属于求最短路径的题目类型。那么我们可以以当前求出的幂的集合为状态,采用IDA*方法即可求解。问题的关键在于如何剪枝效率更高。笔者采用的剪枝方法是:

  1)如果当前状态幂集合中的最大元素max满足 max*2^(maxd-cur_d)<n,则剪枝。原因是:在每一次状态转移后,max最多增大一倍。(maxd-cur_d)次转移之后,max最多变成原来的2^(maxd-cur_d)倍,然而如果当前状态的极限情况下仍有max<n,则当前状态结点一定无法出解。

  2)解的幂集合中最多只有一个元素比目标n大。

采用反证法,证明如下:

  假设解的幂集合中存在m2>m1>n ,那么必然存在从m2到达m1的路径p1,和从m1到达n的路径p2(否则与假设矛盾)。

  设路径p1花费步数s1,路径p2花费步数s2,那么从m2到达n的步数为s3=s2+s1>s2。

  然而由于我们采用IDA*算法,由于s2<s3,路径p2会先被找到,当前状态不会出现,产生矛盾,得证。

有了以上优化思路,代码效率将会极大提高。

代码如下:

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <set>
#include <algorithm>

using namespace std;
#define time__ printf("time : %f\n",double(clock())/CLOCKS_PER_SEC)

int tar_n;
int power[3000+5];
vector<int> S;
int maxd;
int S_upper_n(){
int cnt=0;
for(int i=0;i<S.size();i++)
if(S[i]>tar_n) cnt++;
return cnt;
}
bool dfs(int d){
if(d==maxd){
if(power[tar_n]) return true;
else return false;
}
int S_max=0;
for(int i=0;i<S.size();i++)
S_max=max(S_max,S[i]);
if(((S_max)<<(maxd-d))<tar_n||S_upper_n()>1)
return false;
for(int i=S.size()-1;i>=0;i--){
int t;
t=S[S.size()-1]+S[i];
if(power[t]==0){
S.push_back(t);
power[t]=1;
if(dfs(d+1)) return true;
S.pop_back();
power[t]=0;
}
t=S[S.size()-1]-S[i];
if(t>0&&power[t]==0){
S.push_back(t);
power[t]=1;
if(dfs(d+1)) return true;
S.pop_back();
power[t]=0;
}
}
return false;
}
bool solve(){
memset(power, 0, sizeof power);
S.clear();
S.push_back(1);
power[1]=1;
if(dfs(0))
return true;
return false;
}
int main() {
while(scanf("%d",&tar_n)&&tar_n){
maxd=0;
int temp=1;
while(temp<tar_n){
maxd++;
temp+=temp;
}
for(;;maxd++)
if(solve()){
printf("%d\n",maxd);
//time__;
break;
}
}
//time__;
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: