分治算法学习 Divide and Conquer

分治思想:

     分治算法的思想就是 对于某些特定种类的问题  如果问题的规模很小,那么就直接解决,如果问题的规模比较大,那么就把问题先分解为规模小的但是问题相同的子问题 ,并且不断分解直到规模足够小,再递归地解决这些问题 如果原问题可分割成k个子问题,1<k≤n,且这些子问题都可解并可利用这些子问题的解求出原问题的解,那么这种分治法就是可行的。 递归与分治经常是一起使用的

能够用分治的情况 :

1.问题复杂性随规模减小而减小

2.问题具有最优子结构性质

    

       最优子结构:如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。

例如,最短路径问题有以下最优子结构性质:如果一个节点x是到源节点ü的最短路径,同时又是到目的节点V的最短路径,则最短路径从u到v是结合最短路径:u到x和x到v。解决任意两点间的最短路径的算法的Floyd-Warshall算法和贝尔曼-福特是动态规划的典型例子。

3.分解的问题的解可以合并为该问题的解

  如果问题不能合就不能用分治,这时可以考虑贪心和动态规划 

4.同一个分割级别的各个子问题之间不互相包含 是独立的

    Fibonacci 就不是独立的  因为计算 F(9)=F(8)+F(7)时候已经  包含了 F(8)这个子问题 而由于用的是递归的思想 ,所以 F(8) 会被重复计算,效率不高 子问题互相重叠应该考虑用动态规划 

分治的具体步骤:

很多书都有介绍了 步骤就是:

1.分解 2.解决 3.合并

step1 分解:将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题;

step2 解决:若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题

step3 合并:将各个子问题的解合并为原问题的解。

使用分治的经典问题:

二分搜索

大整数乘法

Strassen矩阵乘法

棋盘覆盖

mergesort 归并排序

快速排序

线性时间选择

最接近点对问题

循环赛日程表

汉诺塔

经典问题解决举例 归并排序

  

依据分治法设计程序时的思维过程

实际上就是类似于数学归纳法,找到解决本问题的求解方程公式,然后根据方程公式设计递归程序。

1、一定是先找到最小问题规模时的求解方法

2、然后考虑随着问题规模增大时的求解方法

3、找到求解的递归函数式后(各种规模或因子),设计递归程序即可。

参考算法导论上的第一章 第二章 "归并排序"

merge过程的伪代码

归并排序的整个过程: mergesort(A,a,b)

 1 /*************************************************************************
 2     > File Name: mergesort.cpp
 3     > Author: VOID_133
 4     > Created Time: 2014年08月06日 星期三 14时17分16秒
 5     > Content : Divide and Conquer Classic Problem
 6                     MergeSort
 7  ************************************************************************/
 8
 9 #include<iostream>
10 #include<cstdio>
11 using namespace std;
12 const int MAX=100000;
13 int L[MAX];
14 int R[MAX];
15 void mergesort(int* A,int first,int end);
16 void merge(int *A,int first,int mid,int end);
17 void mergesort(int* A,int first,int end)
18 {
19     if(first<end)
20     {
21         int mid=(first+end)/2;
22         mergesort(A,first,mid);
23         mergesort(A,mid+1,end);    //Solve the problem recursively
24         merge(A,first,mid,end);
25     }
26     return ;
27 }
28
29 void merge(int *A,int first,int mid,int end)
30 {
31     int lenL=mid-first+1;
32     int lenR=end-mid;
33     for(int i=1;i<=lenL;i++) L[i]=A[first+i-1];
34     for(int i=1;i<=lenR;i++) R[i]=A[mid+i];
35     int li=1;
36     int ri=1;
37     int cnt=first;                        //the array we should merge is from A[first] to A[end] so we can only modify these value ,we shouldn‘tmodify other A values
38     //The Problem has fixed
39     while(li<=lenL && ri <=lenR)
40     {
41         int tmp;
42         if(L[li]>R[ri])
43         {
44             tmp=R[ri];
45             ri++;
46         }
47         else
48         {
49             tmp=L[li];
50             li++;
51         }
52         A[cnt++]=tmp;
53     }
54     while(li<=lenL)
55     {
56         A[cnt++]=L[li++];
57     }
58     while(ri<=lenR)
59     {
60         A[cnt++]=R[ri++];
61     }
62     return ;
63 }
64
65
66 int main(void)
67 {
68     int arr[MAX];
69     int n;
70     while(scanf("%d",&n)!=EOF && n)
71     {
72         for(int i=1;i<=n;i++) cin>>arr[i];
73         mergesort(arr,1,n);
74         for(int i=1;i<=n;i++) cout<<arr[i]<<" ";
75         cout<<endl;
76     }
77     return 0;
78 }

第一次写的时候 由于把合并的原理弄错了 导致代码运行结果异常

合并的时候 只能修改你要合并的那个区间里的元素的值不能修改别的地方的元素的值

归并排序是最简单的分治方法 问题分解为 2个 每个问题的规模是原先的 1/2

分治算法学习 Divide and Conquer

时间: 2024-08-02 02:46:28

分治算法学习 Divide and Conquer的相关文章

分治算法(Divide and Conquer)

分治算法 在计算机科学中,分治法是建基于多项分支递归的一种很重要的算法范式.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并. 分治法所能解决的问题一般具有以下几个特征: 问题的规模缩小到一定的程度就可以容易地解决 问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质 利用该问题分解出的子问题的解可以合并为该问题的解 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问

算法学习——分治算法

这是从网上查到的概念资料,先收来~ 一.基本概念 在计算机科学中,分治法是一种很重要的算法.字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求解的问题所需的计算时间都与其规模有关.问题的规模越小,越容易直接求解,解题所需的计算时间也越少.例如,对于n个

【算法】2 由股票收益问题再看分治算法和递归式

回顾分治算法 分治算法的英文名叫做"divide and conquer",它的意思是将一块领土分解为若干块小部分,然后一块块的占领征服,让它们彼此异化.这就是英国人的军事策略,但我们今天要看的是算法. 如前所述,分治算法有3步,在上一篇中已有介绍,它们对应的英文名分别是:divide.conquer.combine. 接下来我们通过多个小算法来深化对分治算法的理解. 二分查找算法 问题描述:在已排序的数组A中查找是否存在数字n. 1)分:取得数组A中的中间数,并将其与n比较 2)治:

算法学习 :分而治之思想

在刷LeetCode时遇到了一题可以用到分治思想的题目,刚好前段时间有看到过关于分治思想的讲解,但是不是很理解,这里再学习一次. 分而治之(divide and conquer,D&C)--一种著名的递归式问题解决方法. 使用分治解决问题的过程包括两个步骤: 1.找出基线条件,这种条件必须尽可能简单 2.不断将问题分解,或者说缩小规模,直到符合基线条件 编写涉及数组的递归函数时,基线条件通常是数组为空或只包含一个元素. 在实际做题时 只能选择相信这个分治思想是正确的,因为我在看到这种DC解法时

分治算法——Karastsuba算法

分治(Divide and Conquer)算法:问题可以分解为子问题,每个问题是可以独立的解决的,从子问题的解可以构建原问题. Divide:中间分.随机分.奇偶分等,将问题分解成独立的子问题 Conquer:子问题的解可以单独解决,从子问题的解构建原问题最终的解 Combine:每一步将子问题产生的解进行合并得到最终的解,合并的复杂度影响最终的算法时间复杂度 Karatsuba算法是在普通乘法算法的基础上进行的提升,使得最终的复杂度从O(n^2)变为了O(n^1.585),基本思想是将原问题

lanczos算法及C++实现(三)实对称三对角阵特征值分解的分治算法

本文属作者原创,转载请注明出处 http://www.cnblogs.com/qxred/p/dcalgorithm.html 本系列目录: lanczos算法及C++实现(一)框架及简单实现 lanczos算法及C++实现(二)实对称阵奇异值分解的QR算法 lanczos算法及C++实现(三)实对称三对角阵特征值分解的分治算法 0. 参考文献 https://en.wikipedia.org/wiki/Divide-and-conquer_eigenvalue_algorithm A. Mel

分治算法例子集锦

描述: 两部分组成 分(divide):递归解决较小的问题 治(conquer):然后从子问题的解构建原问题的解 三个步骤 1.分解(Divide):将原问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题: 2.解决(Conquer):若子问题规模较小而容易被解决则直接解,否则递归地解各个子问题: 3.合并(Combine):将各个子问题的解合并为原问题的解. 四个适用条件 1.该问题的规模缩小到一定的程度就可以容易地解决: 2.该问题可以分解为若干个规模较小的相同问题,即该问题具有最

分治算法Divide-and-Conquer概述

设计过程分为三个阶段 Divide: 整个问题划分为多个子问题  T(n)=D(n) Conquer:求解各子问题(递归调用正设计的算法)  T(n)=aT(n/b) Combine:合并子问题的解, 形成原始问题的解T(n)=C(n) Note: 将规模为n的问题划分为a个子问题,每个问题的大小为n/b.(b可能不等于a!) 时间复杂度:T(n)=θ(1)     if n<c常数 T(n)=aT(n/b)+D(n)+C(n) 经典问题1:归并排序 Divide阶段:在中间节点节段 时间为O(

我的算法学习之路

关于 严格来说,本文题目应该是我的数据结构和算法学习之路,但这个写法实在太绕口--况且CS中的算法往往暗指数据结构和算法(例如算法导论指的实际上是数据结构和算法导论),所以我认为本文题目是合理的. 这篇文章讲了什么? 我这些年学习数据结构和算法的总结. 一些不错的算法书籍和教程. 算法的重要性. 初学 第一次接触数据结构是在大二下学期的数据结构课程.然而这门课程并没有让我入门--当时自己正忙于倒卖各种MP3和耳机,对于这些课程根本就不屑一顾--反正最后考试划个重点也能过,于是这门整个计算机专业本