首页 > 其他分享 >分治

分治

时间:2023-06-16 20:22:50浏览次数:29  
标签:元素 ++ 分治 合并 low 序列 排序

分治算法

概述

分而治之 ,称之 分治本质 就是将一个大规模的问题分解为若干 规模较小相同子问题 ,分而治之。

本质

可以使用分治算法的情况——问题需要满足一下三个条件:

  1. 原问题可被分解为若干规模较小的相同子问题;

  2. 子问题 相互独立

  3. 子问题的解可以 合并 为原问题的解。

分治算法 求解方法 如下。

  1. 分解 :将原问题分解为若干规模较小、相互独立且与原问题形式相同的子问题。

  2. 治理 :求解各个子问题。由于各个子问题与原问题形式相同,只是规模较小,所以当子问题划分得足够小时,就可以用较简单的方法解决。

  3. 合并 :按原问题的要求,将子问题的解组曾合并形成原问题的解。

一言以蔽之,分治算法是将一个难以直接解决的大问题分割成一些规模较小的相同问题,以便各个击破、分而治之。在分治算法中,各个子问题形式相同,解决方法也一样,因此可以使用递归算法快速解决。

合并排序

在数列中,如果只有一个数,那么它本身就是有序的;如果只有两个数,那么进行一次比较就可以完成一次排序。也就是说, 数越少,排序越容易。 那么,对于一个由大量数据组成的数列,我们很难一次完成排序,这时可将其 分解 为小的数列,一直分解到只剩一个数时,本身已有序,再把这些有序的数列合并在一起,执行一个 和分解相反 的过程,从而完成对整个序列的排序。

合并排序就是采用 分治 策略,将一个大问题 分成 很多个小问题, 先解决小问题,再通过小问题解决大问题 。由于排序问题给定的是一个无序序列,所以可以把待排序元素 分解 成两个规模大致相等的子序列,如果不易解决,则再将得到的子序列 继续分解 ,直到在子序列中包含的元素个数为 1 .因为单个元素的序列本身是有序的,此时便可以进行合并,从而得到一个完整的有序序列。

  1. 算法设计

    合并排序是采用 分治策略 进行 排序 的算法,是分治算法的一个典型应用和完美体现。它是一种 平衡、简单的 二分 分治策略。
    算法步骤如下。

    1. 分解: 将待排序元素分成大小大致相同的 两个子序列
    2. 治理: 对两个子序列进行 合并排序
    3. 合并:排好序 的有序子序列进行合并,得到最终的 有序序列
  2. 图解

    给定一个数列 \((42,15,20,6,8,38,50,12)\) ,执行合并排序的过程如下图所示。

    从上图可以看出,首先将待排序元素分成大小大致相同的 两个子序列 ,然后把子序列分成大小大致相同的 两个子序列 ,如此下去,直到分解成 一个元素 时为止,这时含有一个元素的子序列就是 有序的 ;然后 执行合并 操作,将两个有序的子序列 合并为一个 有序序列,如此下去,直到 所有的 元素都合并为一个有序序列时为止。

  3. 算法设计

    1. 合并操作

      为了进行合并,这里引用一个 辅助合并函数 Merge(A,low,mid,high) ,该函数将排好序的两个子序列 A[low:mid]A[mid+1:high] 进行排序。其中, low、high 代表带合并的两个子序列在数组中的 下界上界mid 代表下界和上界的 中间位置 ,如下图所示。

      这里还设置3个工作指针 \(i 、j 、k\) (整型下标)和一个辅助数组B。其中, \(i\) 和 \(j\) 分别指向 两个 待排序 子序列当前待比较的元素 , \(k\) 指向 辅助数组B待放置元素 的位置。比较 A[ \(i\) ]A[ \(j\) ] ,将较小的赋值给 B[ \(k\) ] ,相应的指针同时向后移动。如此反复,直到所有元素都处理完毕。最后把辅助数组B中排好序的元素 复制 到数组A中,如下图所示。

      第1次比较时,\(A[i]=4,A[j]=2\) ,将较小的元素2放入数组B中, \(j\) ++, \(k\) ++ 。

      第2次比较时, \(A[i]=4,A[j]=6\) ,将较小的元素4放入数组B中, \(i\) ++, \(k\) ++ 。

      第3次比较时, \(A[i]=9,A[j]=6\) ,将较小的元素6放入数组B中, \(j\) ++, \(k\) ++ 。

      第4次比较时, \(A[i]=9,A[j]=18\) ,将较小的元素9放入数组B中, \(i\) ++, \(k\) ++ 。

      第5次比较时, \(A[i]=15,A[j]=18\) ,将较小的元素15放入数组B中, \(i\) ++, \(k\) ++ 。

      第6次比较时, \(A[i]=24,A[j]=18\) ,将较小的元素18放入数组B中, \(j\) ++, \(k\) ++ 。

      第7次比较时, \(A[i]=24,A[j]=20\) ,将较小的元素20放入数组B中, \(j\) ++, \(k\) ++ 。

      此时, \(j\) >high的后半部分已处理完毕,但前半部分还剩余元素,该怎么办?将剩余元素照搬到数组B就可以了。

      完成合并后,需要把辅助数组B中的元素复制到原来的数组A中。

      算法代码:

    void Merge(int A[], int low, int mid, int high) {
    		int *B = new int[high - low + 1];//申请一个辅助数组 
    		int i = low, j = mid + 1, k = 0;
    		while (i <= mid && j <= high) {//按从小到大存放到辅助数组B中 
    			if (A[i] <= A[j]) B[k++] = A[i++];
    			else B[k++] = A[j++];
    		}
    		while (i <= mid) B[k++] = A[i++];//将数组中剩下的元素放置到数组B中 
    		while (j <= high) B[k++] = A[j++];
    		for (i = low, k = 0; i <= high; i ++ )
    			A[i] = B[k++];
    		delete[] B;
    }
    
    1. 合并排序

      将序列分成两个子序列,然后对子序列进行递归排序,再把两个已排好序的子序列合并成一个有序的序列。

      void MergeSort(int A[], int low, int high) {
      	if (low < high) {
      		int mid = (low + high) / 2;//取中点
      		MergeSort(A, low, mid);//对A[low : mid]中的元素合并排序
      		MergeSort(A, mid + 1, high);//对A[mid + 1 : high]中的元素合并排序
      		Merge(A, low, mid, high);//合并
      	}
      }
      
  4. 算法分析

    时间复杂度:分解仅仅是计算出子序列的中间位置,需要常数时间 \(O(1)\) 。递归求解两个规模为 \(n / 2\) 的子问题,所需时间为 \(2T(n / 2)\) 。合并算法可以在 \(O(n)\) 时间内完成。所以总运行时间如下:

    \[T(n)=\begin{cases} O(1) &\text{n=1}\\ 2T(\frac n 2)+O(n) &\text{n>1} \end{cases}\]

    当 \(n>1\) 时,递推求解:

\[\begin{equation} \begin{split} T(n) &=2T(\frac n 2)+O(n)\\ &=2(2T(\frac n 4)+O(\frac n 2))+O(n)\\ &=4T(n/4)+2O(n)\\ &=8T(\frac n 8)+3O(n)\\ &...\\ &=2^xT(\frac{n}{2^x})+xO(n) \end{split} \end{equation}\]

标签:元素,++,分治,合并,low,序列,排序
From: https://www.cnblogs.com/Ifyoung/p/17486447.html

相关文章

  • 递归、分治、动态规划、贪心、回溯、分支限界
    递归、分治、动态规划、贪心、回溯、分支限界 相似算法比较:递归、分治、动态规划、贪心、回溯、分支限界​ 在学习算法的过程中,递归、分治、动态规划、贪心、回溯、分支限界这些算法有些类似,都是为了解决大问题,都是把大问题拆分成小问题来解决,但她们之间还是有一些不同之......
  • 点分治
    询问树上距离为 k 的点对是否存在。#include<bits/stdc++.h>usingnamespacestd;constintMAX=20010;constintinf=1.5e8;intn,m,x,y,z,q[MAX],rt,siz[MAX],maxx[MAX],dis[MAX];vector<pair<int,int>>g[MAX];stack<int>tag;booltf[inf],ret[MAX],vis......
  • Codeforces 1566G - Four Vertices(线段树分治)
    交了整整2页,本来想用随机化卡过去的,后来发现我的实现跑得太慢就写正常做法了。首先发现最优答案对应的四个点只可能有以下两种可能:\(a,b\)间有边,\(c,d\)间有边,此时答案是\(a,b\)边权值加\(c,d\)边权值。\(a\)与\(b,c,d\)三个点间都有边,此时答案是三条边权值之和。......
  • 用分治处理决策单调性问题
    决策单调性是dp转移方程的一种性质。一般而言,我们有许多方法优化一个具有决策单调性的转移方程。这里主要讲解一种用分治解决决策单调性问题的方法。引入先看一道题:CF868F我们可以想到一个\(O(n^2k)\)暴力。定义\(dp_{i,j}\)为令点\(i\)为第\(j\)段的最后一个点产......
  • 分治
    分治法基本介绍分治法,即“分而治之”,对于一个难以解决的大问题,将其分解成k个相同或相似的规模更小的子问题,一直分解直到问题足够小,极容易求解为止。解题步骤分治法建模的大概流程可以分为三步:1.分解:将大问题分解成多个更小的独立且相同或相似子问题,直到子问题容易容易求解2.......
  • 「学习笔记」略谈点分治
    点分治适合处理大规模的树上路径信息问题。引入给定一棵\(n\)个点树和一个整数\(k\),求树上两点间的距离小于等于\(k\)的点对有多少。对于这个题,如果我们进行\(O_{n^3}\)搜索,那只要\(n\)一大,铁定超时。所以,我们要用一个更优秀的解法,这就是我们的点分治。淀粉质可......
  • 不同路径 II(数组、动态规划)、同构字符串(哈希表、字符串)、颠倒二进制位(位运算、分
    不同路径II(数组、动态规划)一个机器人位于一个_mxn_网格的左上角(起始点在下图中标记为“Start”)。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?网......
  • Summary - 分治
    本文旨在总结数种分治算法。1.区间分治:当需要对所有区间统计答案时,可以考虑这种分治。具体来说,在处理\([l,r]\)内的所有区间时,分三类考虑:跨过\(mid\)的,完全在\(mid\)左边的,完全在\(mid\)右边的。如果可以\(O(m)\)或\(O(m\logm)\)处理第一类情形(\(m=r-l+1\)),然后用分治处理另外两......
  • Solution Set - CDQ分治
    A[洛谷P2163].给定平面上若干个点,多次询问给定矩形内的点数。B[洛谷P3810].给定若干个三元组,对所有\(k\),求这样三元组的个数:恰有\(k\)个三元组,满足其每个分量都不超过它的相应分量。C[洛谷P3157].给定一个序列,从中依次删去某些元素,求每次删除前逆序对数目。D[CF762E/CF1045G].......
  • Solution Set - 点分治
    A[POJ1741].给定一棵树,边有权,求长度不超过\(k\)的路径数目。B[HDU4871].给定一张图,边有权,求它的最短路径树上恰含\(k\)个点的路径中最长路径的长度及数目。C[HDU4812].给定一棵树,点有权,求字典序最小的一个点对,其路径上的所有点权之积模\(100003\)等于\(k\)。D[HDU5469].给定一......