分治算法

求最大子数组之和的分治算法

岁酱吖の 提交于 2020-01-18 01:54:47
#include <stdio.h> #include <limits.h> typedef struct _node { int left; int right; int sum; }Node; void findCrossSubArr(int *arr,int low,int mid,int high,Node *crossResult) { int left_sum=INT_MIN; int sum=0; int i=mid; for(;i>=low;i--) { sum=sum+arr[i]; if(sum>left_sum) { left_sum=sum; crossResult->left=i; } } int right_sum=INT_MIN; sum=0; i=mid+1; for(;i<=high;i++) { sum=sum+arr[i]; if(sum>right_sum) { right_sum=sum; crossResult->right=i; } } crossResult->sum=left_sum+right_sum; } void findMaxSubArr(int *arr,int low,int high,Node *result) { if(low==high) { result->left=low; result->right=low;

离线分治算法——CDQ分治详解

a 夏天 提交于 2020-01-17 18:02:55
以前做过的许多题目,都是在线算法,也就是对与一系列的询问,利用某种数据结构逐个求出答案。 而今天学了一种离线算法——CDQ分治,是将全部的询问放在一起,利用分治一同处理。 CDQ分治,由2008年国际信息学奥林匹克竞赛(IOI)金牌女选手陈丹琦在国家集训队中引入而得名,为算法竞赛界中的一个广泛称呼。 CDQ分治有两种,分别是 基于时间的分治 和 基于值域的整体分治 。 下面看就开始吧。 1.基于时间的分治 BZOJ2716–天使玩具 【题意】 Ayu在七年前曾经收到过一个天使玩偶,当时她把它当做时间囊埋在了地下。 而七年后的今天,Ayu却忘了她把天使玩偶埋在了哪里,所以她决定仅凭一点模糊的记忆来寻找它。 我们把Ayu生活的小镇看做一个二维平面直角坐标系,而Ayu会不定时的记起可能在某个点(x,y)埋下了天使玩偶。 或者Ayu会询问你,假如她在(x,y),那么她离最近的天使玩偶可能埋下的地方有多远。 因为Ayu只会沿着平行坐标轴的方向来行动,所以在这个问题里我们定义两个点之间的距离为曼哈顿距离: dist(A,B)=|Ax−Bx|+|Ay−By| 其中Ax,Ay表示点A的横坐标,其余类似。 【输入格式】 第一行包含两个整数n和m,在刚开始时,Ayu已经知道有n个点可能埋着天使玩偶,接下来Ayu要进行m次操作。 接下来n行,每行两个非负整数xi,yi,表示初始n个点的坐标。

快速排序

左心房为你撑大大i 提交于 2020-01-10 02:25:23
排序算法采用了一种分治的策略,即将大模块划分成同样的小模块。 快排的基本思想: 先从数组中取出一个数作为基准数,通常取数组的第一个元素作为基准数 分区过程,将比基准数大的数放到他的右边,小于或等于他的数放到左边 经过一次分区后,便可以将原数组分成基准数的左边都小于等于基准数,而右边都大于基准数的数组。重复第2步的过程,直到区间只有一个数,最终就可以得到一个有序的数组 快速排序实际上就是挖坑+填数+分治的过程。 以一个数组arr为例,取第一个数作为基准数 0 1 2 3 4 5 6 7 8 9 72 6 55 80 60 90 42 73 48 100 初始时 i=0,j=5,x=arr[0]。 由于已经将arr[0]保存到x了,所以arr[0]可以被其他数填充了,相当于在arr[0]上挖了个坑。 j从右向左遍历数组,找第一个小于等于x的数,在j=8的位置满足要求,将arr[8]挖出填到arr[0]中,同时i++,此时arr[8]多出一个坑位,等待其他数填充。i从左向右遍历,找到第一个比x大的数,i=3符合要求,将arr[3]的数取出填到arr[8]中,同时j--,数组变为 0 1 2 3 4 5 6 7 8 9 48 6 55 80 60 90 42 73 80 100 此时i=3,j=7,x=72; 再重复上面的步骤,先从后向前找,再从前向后找。 从j开始向前找,j=6,符合条件

五大常见算法策略之——递归与分治策略

岁酱吖の 提交于 2020-01-08 11:50:46
递归与分治策略 递归与分治策略是五大常见算法策略之一,分治策略的思想就是 分而治之 ,即先将一个规模较大的大问题分解成若干个规模较小的小问题,再对这些小问题进行解决,得到的解,在将其组合起来得到最终的解。而分治与递归很多情况下都是一起结合使用的,能发挥出奇效(1+1>2),这篇文章我们将先从递归说起,再逐渐向分治过渡,主要讲解方式是通过9个例题来说明问题的,问题都是根据难度由简到难,由浅入深,对递归与分治能有个大概的了解雏形,当然最重要还是要做大量练习才能掌握。 0、递归    0.0、Fibonacci数列(易)    0.1、阶乘(易)    0.2、小青蛙跳台阶(易)    0.3、全排列问题(偏难)    0.4、整数划分(偏难) 1、分治策略    1.0、归并排序(一般)    1.1、二分查找(易)    1.2、棋盘覆盖(偏难)    1.3、日程表问题(偏难) 递归 我们第一次接触递归一般都是在初学C语言时候的一道题目——Fibonacci数列中看到的,可能刚开始感觉有点不可思议,函数居然可以调用自己!Amazing!但事实如此,它确实存在,而递归也为我们某些算法的设计提供很大的便利,一般来说递归函数在理解起来并不是很难,甚至可以通过数学归纳法给予证明,但一直让人诟病的一点莫过于Debug的时候了,有时候调试一个较为复杂的递归函数能把人逼疯。 我们在这里将会

前端工程——基础篇

狂风中的少年 提交于 2020-01-07 08:31:11
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> # 前端工程——基础篇 > 喂喂喂,那个切图的,把页面写好就发给研发工程师套模板吧。 你好,切图仔。 不知道你的团队如何定义前端开发,据我所知,时至今日仍然有很多团队会把前端开发归类为产品或者设计岗位,虽然身份之争多少有些无谓,但我对这种偏见还是心存芥蒂,酝酿了许久,决定写一个系列的文章,试着从工程的角度系统的介绍一下我对前端,尤其是Web前端的理解。 只要我们还把自己的工作看作为一项软件开发活动,那么我相信读过下面的内容你也一定会有所共鸣。 ## 前端,是一种GUI软件 现如今前端可谓包罗万象,产品形态五花八门,涉猎极广,什么高大上的基础库/框架,拽炫酷的宣传页面,还有屌炸天的小游戏……不过这些一两个文件的小项目并非是前端技术的主要应用场景,更具商业价值的则是复杂的Web应用,它们功能完善,界面繁多,为用户提供了完整的产品体验,可能是新闻聚合网站,可能是在线购物平台,可能是社交网络,可能是金融信贷应用,可能是音乐互动社区,也可能是视频上传与分享平台…… > 从本质上讲,所有Web应用都是一种运行在网页浏览器中的软件,这些软件的图形用户界面(Graphical User Interface,简称GUI)即为前端。 如此复杂的Web应用,动辄几十上百人共同开发维护,其前端界面通常也颇具规模

初涉点分治

这一生的挚爱 提交于 2019-12-30 02:50:33
不能说是一个算法,应该算是一类思想 点分治 概念 点分治就是把树上问题中的节点拿来 分治 。 这所谓的“分治”是一个很抽象的概念,那么就先来介绍它的常见应用和其他性质。 大致框架 1 void getRoot(int x, int fa) //找重心 2 { 3 size[x] = 1, son[x] = 0; 4 for (int i=head[x]; i!=-1; i=nxt[i]) 5 { 6 int v = edges[i].y; 7 if (v==fa||vis[v]) continue; //在点分树内寻找重心 8 getRoot(v, x), size[x] += size[v]; 9 son[x] = std::max(son[x], size[v]); 10 } 11 son[x] = std::max(son[x], tot-size[x]); 12 if (son[x] < son[root]) root = x; //root即重心 13 } 14 void dfs(int x, int fa, int c) 15 { 16 record distance_c //将长度为c的路径记录下来 17 for (int i=head[x]; i!=-1; i=nxt[i]) 18 { 19 int v = edges[i].y; 20 if (v==fa||vis

POJ 1741 - Tree - [点分治]

為{幸葍}努か 提交于 2019-12-30 02:28:35
题目链接: http://poj.org/problem?id=1741 Time Limit: 1000MS Memory Limit: 30000K Description Give a tree with n vertices, each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. Write a program that will count how many pairs which are valid for a given tree. Input The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which

点分治

依然范特西╮ 提交于 2019-12-30 02:21:56
点分治是个好东西 学长说今年省选day2 T3 有40分可以是点分治 有点难受如果我当初学了点分治该有多好啊。 所谓点分治就是在树上搞一些分治操作让复杂度大大降低。 这道题询问树上是否有任意两点之间的距离为k 考虑暴力 m指询问数 暴力枚举 加dfs跑距离 所以复杂度是mn^3 期望得分 30 由于是一棵无根树所以考虑以1位根节点提前预处理出树上任意点距根的距离。 然后 暴力枚举两个端点 求出LCA 然后 d[x]+d[y]-(d[LCA]<<1)判断即可。 复杂度 mn^2logn期望得分60 很不错了~ 正解释点分治:其实点分治是一种另类的分治方法基于树上的分治。 先处理过根的边 然后分治处理根的子树这样递归处理 考虑每次选根都是树的重心处。 所以总递归层数为logn 在每一层中暴力判断和过根的边的联系的边然后进行判断复杂度O(n) 总复杂度mnlogn 期望得分:100;这样巧妙的利用了分治思想和不断的选择重心 使复杂度骤降。 因为一些小细节打挂了所以浪费了点时间来检查。 首先是对于树的重心的处理 然后是分治点 然后在每个点中进行答案的统计即可。 复杂度mnlogn 可以AC。 //#include<bits/stdc++.h> #include<iostream> #include<cstdio> #include<iomanip> #include<cstring>

点分治详解

本小妞迷上赌 提交于 2019-12-30 02:19:40
点分治详解 一.概念 ​ 是处理树上路径的一个极好的方法。如果你需要大规模的处理一些树上路径的问题时,点分治是一个不错的选择。 二.具体思路 ​ 大多数同学的暴力做法都是对于每一个点对(u,v) 进行dfs来求解。但其实利用分治这一种算法,可以大大减少搜索的时间复杂度。 ​ 对于一个序列上的区间和等操作,我们可以使用分治来将原问题分解成几个子问题来求解,之后在一一合并答案。而在树上我们也是可以进行这一种操作的。可是树上的每一个子树的节点数是不确定的,不能单单的取中点(你告诉我怎么取),或直接取一号子树。(分治的点的错误选择会导致时间复杂度十分不稳定)。 ​ 如下图所示,如果你取了第一个点的话,那么时间复杂度会变 \(O(n)\) ,但如果我们取的点是3的话,那么时间复杂度就会是 \(O(logn)\) ​ 所以,我们要引入一个概念 —— 树的重心 ​ 定义: 找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡 ​ 由定义可知,当我们选择树的重心为分支点时,是最优的( 我有个绝妙的证明只是这里写不下 ) ​ 好了,求出了树的重心之后我们就可以来分治了!! ​ 先现给出求重心的代码,便于读者依次理解 void find(int x,int fa) { size[x] = 1; mx[x] = 0; for (int i =

关于点分治的理解

 ̄綄美尐妖づ 提交于 2019-12-30 02:14:45
【引言】 由于树具有一般的图没有的特点,所以在竞赛中的应用更广。 在一些树上路径问题中,暴力求解时间复杂度过高,往往需要一些更为高效的算法,点分治就是其中之一。 【流程】 1、首先选取一个点,把无根树变成有根树。   那么如何选点呢? ——树型动规   因为树是递归定义的,所以我们当然希望递归的层数最小。   每次选取的点,要保证与此点相连的结点数最多的连通块的结点数最小,我们把这个点叫做“重心”。   那么找到一颗树的重心有以下算法:   (1)dfs一次,算出以每个点为根的子树大小。   (2)记录以每个结点为根的最大子树的大小。   (3)判断:如果以当前结点为根的最大子树大小比当前根更优,更新当前根。 1 void getroot(int x,int fa)//x表示当前结点,fa表示x的父结点 2 { 3 son[x]=1;F[x]=0;//F数组记录以x为根的最大子树的大小 4 for(int i=Link[x];i;i=e[i].next) 5 if(e[i].y!=fa&&!vis[e[i].y])//避免陷入死循环 6 { 7 getroot(e[i].y,x);//得到子结点信息 8 son[x]+=son[e[i].y];//计算x结点大小 9 F[x]=max(F[x],son[e[i].y]);//更新F数组 10 } 11 F[x]=max(F[x]