分治算法

浅谈分治算法

主宰稳场 提交于 2019-11-30 12:30:40
浅谈分治算法 本篇随笔讲解信息学奥林匹克竞赛中的 分治算法 。分治算法更多的是一种思想,不仅是一种算法本身,以后的很多高级算法和数据结构(比如分块),都是分治思想的一种应用。好好体会分治思想,对算法竞赛的思维开发非常有帮助。 分治的概念 分治:字面上的意思就是“分而治之”,简单来说,就是把一个难搞的大问题拆分成很多相对来讲容易搞的小问题,然后把小问题的答案合并起来,导出大问题的答案。是为分治。 分治的适用范围 1、首先,大问题拆成小问题一定要变得更容易解决,否则的话,大问题被拆分之后变得更难了或者并没有什么变化,还拆它干什么。 2、拆成的问题一定是相同种类的,可以进行类比解决。即递归思想。要不然你还想把每个小问题单设计一个算法? 3、分解之后的问题统计出的答案要对大问题的答案有所贡献。意思是说,解决小问题之后要可以合并。 4、小问题之间要相互独立。 分治的步骤 我们可以用树形结构来类比分治算法的实现过程。 假设要求解的大问题是这棵树的根节点。那么整棵树就是分治的过程,叶子节点就是我们要解决的最好的问题。 刚才已经说过,分治的定义更多的偏向于一种思想。下面用一个例子来让大家深入地体会分治思想。 全排列问题 没错,这是一道搜索题。 但是里面的确体现了分治思想(滑稽肯定) 大问题是求出所有的排列方式。 拆分成小问题就是以1开头、以2开头......以n开头。 然后继续拆分,第二位是1

P4149 [IOI2011]Race 点分治

孤人 提交于 2019-11-30 02:06:59
  题意:给定一棵有边权的树 和一个k 问最少多少边(连续)的长度和为k 解法一(也是我一开始的写法) 遍历所有的边 并且给每个边设置一个标记属于某课子树 然后用lowerbound和upperbound找到满足的边 遍历一遍统计答案 用了4s 解法二(只用2s) 边数太多的时候上面的算法复杂度接近 n^2logn QAQ 可以做成3n的 并且每一棵每一棵子树得统计答案和更新子树情况 (先统计 后更新) 就可以避免统计的边不是最短路的情况 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////////// const int N=2e5+10; int n,m,cnt,d[N],head[N],pos,siz[N],sum,x,y,z,ans,vis[N]

递归与分治

人盡茶涼 提交于 2019-11-29 21:50:12
一、递归与分治概述: 1、分治方法在于分和治。将一定规模的问题划分成性质相同的若干个小问题,分;对于每个小问题,进行所需要进行的操作,如排序等。 2、关于递归: (1)递归中需要的成分是递归边界和递归规则,没有递归边界递归无法停止、无法进行。 (2)通过将各层的关系从小到大逐渐带入,可以求解出一个函数的非递归表达式。 (3) n 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。 3、Ackerman函数: Ackerman函数的定义为: 根据关系可以递推出来: 在m取不同的值的过程中,该函数的递推关系式也不同。只是一种无法用单一的非递归关系表达的函数。 4、在Ackerman函数中,定义它的逆拟函数α(n)为使A(x)>n成立的最小的x。 5、整数划分问题: 对于整数的不同划分,考虑以下几种不同的情况:(1)m>n:q(n,m)=q(n,n) (2)m=n:q(n,m)=1+q(n,m-1) (3)m<n:q(n,m)=w(n,m)+q(n,m-1) 又:w(n,m)=q(n-m,m) (4)m=1:q(n,1)=1 6、汉诺塔问题: 思路:将前n-1个元素移动到c上,然后将第n个移动到b上,再将c上的n-1个移动到b上。 注意边界条件是:如果只有一个元素,直接move到b上。 void Move(int no,char a,char b){ printf(

启发式分治入门 Non-boring sequences UVA - 1608

五迷三道 提交于 2019-11-29 18:01:44
参考自: https://blog.csdn.net/XY20130630/article/details/50635756 题意:一个序列被称为是不无聊的,仅当它的每个连续子序列存在一个独一无二的数字, 即每个子序列里至少存在一个数字只出现一次。 给定一个整数序列,请你判断它是不是不无聊的。 分析:预处理每个元素上一次出现位置和下一个出现位置,   我们发现对于一个子序列[L,R]来说,   如果存在pre[i]<L&&nxt[i]>R那么这个子序列一定是满足条件的,   否则就不满足,那么我们分治处理这个问题,   从两边往中间寻找这个i,那么每次拆开的复杂度就是拆成的两个序列中较小的一个,   所以这是一个逆启发式合并的过程,复杂度O(nlogn) 一、在区间[l,r]找到一个只出现一次的元素P(如果不存在,那么序列无聊) 二、递归处理区间[l,p−1]和区间[p+1,r] 关键在于如何找到一个只出现一次的元素。 首先,我们得知道如何判断一个元素是不是只出现一次。 我们可以用STL中的map记录与当前元素值相同的上一个元素(下一个元素)的位置,然后滚动更新即可。 因为 map的所有操作都是O(logn) 的,所以预处理的时间复杂度为O(nlogn) 所以,我们就可以用O(1)的时间判断出一个元素是不是只出现一次了。 若从左到右扫描整个序列,那么 最坏情况

[笔记]点分治

一笑奈何 提交于 2019-11-28 22:47:25
基本思路:点分治,是一种针对 可带权树上简单路径统计问题 的算法。对于一个节点,只解决经过这棵子树的根节点的路径,对于子节点问题下推子树。 //当初的主要问题是vis[]在干什么qwq,终于知道了 #include<iostream> #include<cstdio> #include<algorithm> #define R register int using namespace std; #define ull unsigned long long #define ll long long #define pause (for(R i=1;i<=10000000000;++i)) #define In freopen("NOIPAK++.in","r",stdin) #define Out freopen("out.out","w",stdout) namespace Fread { static char B[1<<15],*S=B,*D=B; #ifndef JACK #define getchar() (S==D&&(D=(S=B)+fread(B,1,1<<15,stdin),S==D)?EOF:*S++) #endif inline int g() { R ret=0,fix=1; register char ch; while(!isdigit(ch

分治思想的案例

社会主义新天地 提交于 2019-11-28 20:52:50
分治思想是一种经典算法思想。为了时常可以回顾,这里记下我遇到的分治思想案例!本博文长期更新,欢迎交流! 1、农场主分割土地: 假设你是一个农场主,有一块小土地,1680*640那么大,你要将这块土地均匀的分成方块,要使分出的方块足够大,应该怎么分? 思路:分治的核心就是每次都把大问题变成一个个小问题,每次递归都缩小问题的规模,然后就是描述出解决问题的基线条件(较简单的描述) 此题的一种基线条件是分出更小的土地时一条边的长度是另一条边的整数倍,主函数的做法:从土地较短的那条边入手,画正方形,直到留下一块小土地,然后对小土地 判断 如果满足基线条件(一边是另一边的整数倍,则表示可以画出该倍数个小方块)则较短边即为最大的方块的边长,否则对这块小土地继续调用主函数,直到找到位置 本题数据:1680*640 => 400*640 => 240*400 => 240 *160 => 80*160(满足基线条件),从基线这里逆推,把之前大的方格全都可以化成80*80的小方格! 案例来源:《算法图解》 来源: https://www.cnblogs.com/FlyingZiming/p/11427424.html

算法思想——分治算法

久未见 提交于 2019-11-28 18:43:35
一、分治策略   “分而治之”,大问题能够拆成相似的小问题,记住这些小问题需要具有相似性。而后将小问题的每个解合成为大问题的解。所以说大问题如何拆,小问题如何合并才是这个算法最主要的一个思想。实际上很多算法如贪心算法,动态规划等等都是要求把大问题拆成小问题。而分治算法的重要一点就是要适用于能够重新把小问题的解合并为大问题的解。 二、分治法适用条件   1、该问题的规模缩小到一定程度就可以很容易解决;   2、该问题可以分解为若干个规模较小的相同问题,这里注意是最优子结构性质;   3、利用该问题分解出的子问题的解可以合并为该问题的解;   4、该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共子问题;   对于很多算法而言,第一条往往是必要的,因为数据量一旦大起来,问题往往复杂度上升的特别快。这里就需要将这个大问题分解为小问题。小问题处理起来更加方便。第二、三条的才是分治思想的核心,因为很多时候我们会采用递归的方式进行解决,所以在大问题分解为小问题的时候需要保证小问题之间的相同性。单单分解为小问题之后还不能算完成,必须要能够将小问题的解合并为这个问题的最终解才能算真正用到了分治的思想。最后一条也是最关键的,各个子问题之间必须要保证独立性,即不互相影响。如果相互之间有影响,这时候我们采用的是动态规划就更加好一点。 三、例题   其实算法的思想不用讲太多

排序算法--归并排序

风格不统一 提交于 2019-11-27 14:15:06
这次备忘一下归并排序。归并排序是分治方法的典型应用。 步骤 :1、把序列分成元素个数尽量相等的两半 2、把两半元素分别排序 3、把两个有续表合并 其中,分治使用的是递归,出口就是被分到的组元素个数小于等于1 分析 :先看时间复杂度,涉及二分的,一般就是O(nlogn)。稳定性方面,相等元素被分到二个组中,合并的时候并不会出现顺序颠倒,所以是稳定的。空间复杂度方面,需要一个临时存储数组,为O(N). 代码展示 : public class MergSort { public static void main(String[] args){ int[] target = {1,10,2,5,7,3,5,8}; int[] tmp = new int[target.length];//建一个临时存储数组 new MergSort().merg_sort(target, 0, target.length, tmp); System.out.print("Result:"+" "); for(int k : target) System.out.print(k+" "); } public void merg_sort(int[] target,int x,int y,int[] tmp){ if(y-x>1){//程序传进来的y是需要排序数组段最后一个元素的下一个元素下标 int m =

CDQ分治&&整体二分

南楼画角 提交于 2019-11-27 08:30:40
以下资料参考自 Owen_codeisking大佬的博客 一、 \(CDQ\) 分治 首先,建议各位小盆友先前置一下树状数组和分治的知识 1.二维偏序 题目: 【模板】二维偏序 && HDU1541 Stars 二维偏序问题:给你 \(n\) 个点,以及这 \(n\) 个点坐标 \(X_{i}\) 和 \(Y_{i}\) ,令 \(F{i}=X{j}\le X{i}且Y{j}\le Y{i}\) 的点的个数,求 \(F{i}\) 这一看,当然可以用暴力解法,最暴力的可以达到 \(O(n^2)\) 的时间复杂度,但只能在 \(n\le5000\) 时用 但如果 \(10000\le n\) 呢? 或许您有 \(n^2\) 过百万的经历(那是因为您是大佬),但下面我们就介绍一种 \(O(nlogn)\) 的算法: \(CDQ\) 分治最基础的运用 我们把这个问题看成一张图(偷来的) 那么,图中被圈起来的点就是对于矩形右上角满足条件的点 首先,我们先将点的纵坐标 \(y{i}\) 从小到大排序(排序横坐标还是纵坐标看心情(随便)),这个用一个 \(sort\) 就可以实现 接着,我们保证了 \(y{i}\) 的从小到大后,就开始对横坐标进行排序 这个排序操作可以用树状数组实现 int c[N]; void add(int x,int y) { for(;x<=N;x+=lowbit(x)

友链

扶醉桌前 提交于 2019-11-26 11:06:19
同届 chdy startaidou Faullest blng melody AK-ls Tyouchie millope yycdeboke gcfer BIGBIGPPT 神犇 zkw byvoid hzwer PoPoQQQ matrix67 yyb Tangenter ⚡cdecl⚡ 学长 Cydiater chty 137shoebills xorex qywyt my_snowing strangedddf UnicornXi left_right Cyxhsa rain under sea mdb jlfeng toughyt 常用网站 魔方小站 OIer博客 马同学高等数学 懒得画图论的同学有福啦 在线手写公式识别 NOIp dqcsm1964 宣传视频 2018年山东科技大学ACM编程竞赛协会纳新宣传视频 2016年成都七中OI队宣传视频 数论 数论知识总结——史诗大作(这是一个flag) OI数学知识 感受一下无穷的公式 解析几何入门 Dp 状压DP详解(位运算) 背包问题 DP 动态规划初步——各种子序列问题 图论 C++迪杰斯特拉算法求最短路径 图的存储结构之邻接表(详解) 图论中的割点,割边,圈与块 Tarjan 浅析强连通分量(Tarjan和kosaraju) Tarjan算法:求解图的割点与桥(割边) 双连通分量 tarjan求强连通分量+缩点+割点