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; }
相关文章推荐
- STM8S103 LCD5110例程带字库
- C内存分配
- sprintf 引起缓冲溢出
- ubuntu下如何查看某端口被占用的情况
- cin和getline混用的问题 与cin.ignore();
- 专题一 · 1004
- 关于求N个无序数中第K大的数。
- Matlab中以三维的方式显示灰度图像
- 字符数组和指针不等价
- linux skype的安装
- 文件下载设置
- NYOJ840 吃花生
- nyoj 115 城市平乱【最短路】
- Gson,FASTjson 解析字符串为数组,日期等方式
- FZU 2102 Solve equation (进制转换)
- 旅行者
- 线段树区间更新模板(lazy延迟标记)(1698)
- 指针常量 和 常量指针
- Python 练习册,每天一个小程序(0005)
- strlen返回的是size_t数据转化为short可能溢出