一本通例题埃及分数—题解&&深搜的剪枝技巧总结
一、简述:
众所周知,深搜(深度优先搜索)的时间复杂度在不加任何优化的情况下是非常慢的,一般都是指数级别的时间复杂度,在题目严格的时间限制下难以通过。所以大多数搜索算法都需要优化。形象地看,搜索的优化过程就像将搜索树上没用的枝条剪下来,因此搜索的优化过程又叫剪枝。剪枝的实质就是通过判断决定是否要沿当前枝条走下去。
二、搜索的剪枝必需遵循三个原则:
1、正确性(不能把正解排除,要不然搜什么呢?)2、准确性(尽可能把不能通向正解的枝条剪去)3、高效性(因为在每个枝条上都要进行一次判断,如果判断的复杂度很高,也会相应地给总复杂度“加料”)
三、剪枝的常用入手点(上面说的都是套话,下面可是干货了)
1、搜索顺序(例如有些题要求不能重复且解中最大值在所有解的最大值中最小的最优解,可以按照从小到大设计搜索,否则其他顺序不仅搜索效率低,代码相应也会很繁琐);
解释一下为什么书中说不一样的搜索顺序,相应的搜索树的形态结构也不一样:当不加任何剪枝时,最直观的体现就是树从根节点开始分支不一样多。因为最终的可行解是一样多的(先不考虑最优性排除的非最优解),而只有搜索树搜到了叶节点才会搜到可行解。如果搜索深度也一样,那么两个搜索顺序对应的搜索树即为两个深度、叶节点树相同,但节点分支的递增顺序不同(可能是一个数较浅地方的分支较小,另一个反之...)。进行剪枝后,情况就不一样了:剪枝时,若剪去的枝条规模越大,那么剪枝也就越成功。那么,在一定的深度剪枝时,对更深的地方分支多的那颗搜索树剪枝的效果就要比对另一颗更深的地方分支少的搜索树剪枝的效果好。因此在剪枝判断很难继续优化的前提下,搜索顺序也会很大程度地影响剪枝的效果。
2、搜索对象:不一样的搜索对象,一般相应的复杂度也不一样。
3、可行性剪枝:当搜索到一个节点时,发现已经不能通向解,就立即回溯。更强一步:对以后的节点,只走能通向解的节点。
*上下界剪枝:有些题仔细分析会发现一个节点的分支是有一个区间,要靠我们分析出区间的上下界,叫上下界剪枝(可行性剪枝中非常常用的一类剪枝,以至于都有自己的名字了(滑稽))。
4、最优性剪枝:当搜索到一个节点时,发现当前状态已经比已得到的最优解差,这是无论向下走的策略再怎么好,也不能比已知解更优,所以立即回溯。更强一步:发现当前状态在未来不会优于已知最优解回溯。
5、排除等效冗杂/记忆化:当发现当前状态已经搜过(记忆化),或当前状态的等效状态已经搜过,就不往下搜了。
小总结:搜索时面临的状态其实都有多个“维度”,或是说多个方面(长度,体积,位置,顺序,密度,增长率至整体的每个基础的组成元素等等),这些维度常常出现在题目描述、给出的变量、要求求的解中。仔细阅读,找到这些维度,结合题目的约束条件或这些维度自己本身的性质,思考剪枝的入手点,根据可行性、最优性或界限列出有关当前花费的不等式,即为初步剪枝。初步剪枝不足以满足AK的可以再考虑列出有关未来花费的不等式(有时用到预处理),还可以再结合各维度之间的关系(例如圆半径与面积、位置与重力势能的关系等等,能懂就好)列出判断用不等式。这不就是推导不等式嘛。
看看例题吧:
条件少得可怜,抛过来一个问题就让我们做,显然是一道搜索题。但是我们不知道到底要用多少个加数,也不知道加数的分母要枚举到多大,这就是这道题的难点。
由于决定最优解的第一条件是加数的个数,所以我们可以先枚举加数的个数limit,尝试limit个单位分数将a/b分解(迭代加深搜索)。为了避免重复搜索,假设第一个单位分数>第二个单位份数>第三个单位分数>....;即第一个分母<第二个分母<第三个分母...这样我们确定的搜索顺序——个数从小到大,对于每个个数,分母从小到大。
设当前的分母为xk,a/b还剩rest没有分解完,因为1/xk+1/xk+1+..+1/xlimit=rest,1/xk>1/xk+1>...>1/xlimit,所以1/xk>rest/(limit-k+1),即xk<(limit-k+1)/limit。因为1/xk<rest,所以xk>1/rest。因为分母按从小到大的顺序搜索,所以xk有大于xk-1。这样就进行了一波强大的上下界剪枝。
当xk>=已知解的最大的分母maxans时,再进行下去也没有意义了(因为无论如何解都不会被这条路径更新了),所以xk<maxans。又进行了一波最优性剪枝。
TIP:对于分数的存储,最好不要算出值来存,因为浮点数总是有误差的,虽然一开始的误差很小,但在在大量的运算下,很容易就把误差放得很大,很大,很大(重要的事情说三遍),所以最好用分子分母存储法。但也注意分子分母可能也很大,很大,很大(重要的事情说三遍),因此别忘了数据类型开大点,能约分就约分(约分有时还能直接撞到最优解)。
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring> using namespace std; int bj,len;
long long ans[],an[],maxans=0x7fffffffffffff; long long gcd(long long a,long long b)
{
return a%b?gcd(b,a%b):b;
} int ok(int k)//判断是否更优
{
if(!len)
{
len=k;
bj=;
maxans=an[k];
return ;
}
if(an[k]<maxans)
{
maxans=an[k];
return ;
}
return ;
} void dfs(int limit,int lst,int k,long long zi,long long mu)
{
if(k==limit)
{
if(zi==&&mu>an[k-])
{
an[k]=mu;
if(ok(k)) memcpy(ans,an,sizeof(long long) * (k+));
}
return;
}
long long li=(limit-k+)*mu/zi-((limit-k+)*mu%zi==);
long long a1,b1;
for(int i=max((long long)lst+,mu/zi+);i<=li&&i<maxans;i++)//上下界剪枝+最优性剪枝
{
an[k]=i;
a1=mu*i;//模拟分数通分再加减的过程
b1=zi*i-mu;
long long g=gcd(b1,a1);
dfs(limit,i,k+,b1/g,a1/g);
}
} int main()
{
// freopen("fraction.in","r",stdin);//调试用
// freopen("fraction.out","w",stdout);
long long a,b;
cin>>a>>b;
long long g=gcd(a,b);
a/=g;b/=g;
if(a==)
{
cout<<b;
return ;
}
for(int i=;;i++)//枚举加数个数
{
dfs(i,,,a,b);
if(bj) break;
}
for(int i=;i<=len;i++)
printf("%lld ",ans[i]);
return ;
}
一本通例题埃及分数—题解&&深搜的剪枝技巧总结的更多相关文章
- 深搜的剪枝技巧(三)——Sticks(可行性剪枝、上下界剪枝、最优性剪枝)
小木棍(最优性剪枝.可行性剪枝) 一.问题描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,已知每段的长都不超过 50 .现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍 ...
- 【笔记】「pj复习」深搜——简单剪枝
深搜--简单剪枝 说在最前面: 因为马上要 NOIP2020 了,所以菜鸡开始了复习qwq. pj 组 T1 ,T2 肯定要拿到满分的,然后 T3 , T4 拿部分分, T3 拿部分分最常见的做法就是 ...
- 深搜+DP剪枝 codevs 1047 邮票面值设计
codevs 1047 邮票面值设计 1999年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description ...
- 【深搜加剪枝】【HDU1455】【Sticks】
题目大意:有一堆木棍 由几个相同长的木棍截出来的,求那几个相同长的木棍最短能有多短? 深搜+剪枝 具体看代码 #include <cstdio> #include <cstdlib& ...
- hdu 1010 Tempter of the Bone(深搜+奇偶剪枝)
Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Othe ...
- LOJ P10022 埃及分数 题解
每日一题 day62 打卡 Analysis 这道题一看感觉很像搜索,但是每次枚举x∈(1,10000000)作为分母显然太蠢了. 所以我们要想办法优化代码. 优化一:迭代加深 优化二: 我们确定了搜 ...
- HDOJ/HDU Tempter of the Bone(深搜+奇偶性剪枝)
Problem Description The doggie found a bone in an ancient maze, which fascinated him a lot. However, ...
- POJ-1190-生日蛋糕(深搜,剪枝)
生日蛋糕 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 23049 Accepted: 8215 Description 7月1 ...
- [Vijos1308]埃及分数(迭代加深搜索 + 剪枝)
传送门 迭代加深搜索是必须的,先枚举加数个数 然后搜索分母 这里有一个强大的剪枝,就是确定分母的范围 #include <cstdio> #include <cstring> ...
随机推荐
- codeforces 1156E Special Segments of Permutation
题目链接:https://codeforc.es/contest/1156/problem/E 题目大意: 在数组p中可以找到多少个不同的l,r满足. 思路: ST表+并查集. ST表还是需要的,因为 ...
- 【Linux开发】【Qt开发】QT 同时支持鼠标和触摸屏
QT 同时支持鼠标和触摸屏 现在 如果我要使用鼠标 导入环境变量 export QWS_MOUSE_PROTO=MouseMan:/dev/input/mice 使用触摸屏,导入环境变量 export ...
- HTTPS测试
1.首先理解HTTPS的含义,清楚http与HTTPS的区别 2.相对于http而言,https更加安全,因 3.使用数字证书使传输更安全,数字证书使用keytool工具生成 测试准备: 创建公钥和秘 ...
- 只需要2个工具,百度云盘大文件就能用迅雷和IDM下载
不会代码,不懂脚本,没关系 ,能找到一座通往它们的桥梁,照样能到达彼岸. 这里以360极速浏览器为例. 在浏览器地址框输入以下地址直接到达浏览器安装扩展插件的地方(偷个懒,复制网址吧),https:/ ...
- CentOS下搭建docker+.net core
运行环境: CentOS 7.0 容器:Docker 1.13.1 .Net Core版本: .NET Core 2.1,安装详见 CentOS 7 下安装.NET Core SDK 2.1 1.安装 ...
- [AGC040B]Two Contests
Description 给出若干条线段 \((L[i], R[i])\) ,把他们分成两个非空的集合,最大化集合内线段交的和. \(n\le 10 ^ 5\) Solution 考虑最小的一个右端点 ...
- fidder抓包工具使用方法,完整流程
fidder抓包工具使用方法,完整流程 https://blog.csdn.net/lw545034502/article/details/82150779 版权声明:本文为博主原创文章,遵循 CC ...
- C++ 线性表实现
List.h #pragma once #include "targetver.h" #include <stdio.h> #include <tchar.h&g ...
- 环境变量和Path环境变量
环境变量 百度百科下的定义 一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:临时文件夹位置和系统文件夹位置等. 环境变量是在操作系统中一个具有特定名字的对象,它包含了一个或者多个应用程序所 ...
- 2019牛客暑期多校训练营(第八场) - B - Beauty Values - 水题
https://ac.nowcoder.com/acm/contest/888/B 实际上的确是个水题,写个小数据找个规律看看,所谓不同度,其实就是依次插入每个元素后,各种元素出现的最后位置的坐标求和 ...