分治算法
基本思想理解
通过阅读博客理解:
- 分治算法是将一个大问题分解成相应的类型相同或者相似的子问题求解,然后在将子问题最后合并为大问题。
- 分治方法与递归技术密不可分。
分治方法适用情况
- 能够拆分成多个相同或者相似的子问题提高算法效率。递归思想
- 子问题的解能够合并成为原来问题——涉及贪心算法以及动态规划算法的择优选择
- 子问题的解相互独立
分治方法基本步骤
- 分:将问题分解为若干个规模较小的,相互独立的,与原问题形式相同的子问题
- 解:当问题小于一个阈值的时候,直接求解。否则不断递归子问题
- 合:将子问题的解合并成为原问题的解
//伪代码
|p|表示问题P的规模;n表示某一个阈值;ADHOC(P)表示子算法——用于求解最小规模的问题;MERGE(y1,...,yi)———合并算法;
if(|p|<n)
{
return ADHOC(P);
}
else
{
不断将子问题通过题目适应的递归算法分解
for(i=1->k)
do yi<-DivideAndConquer(Pi)//递归解决Pi
result <- MERGE(Y1->Yi);
return result
}
涉及题目
二分查找(例题)
题目描述:实现二分搜索:多组输入数据,每组第一个数字为数组的长度n,然后输入n个整数,最后输入带查询的数值m.
非递归方式
//运用非递归方式实现二分查找
#include <stdio.h>
#define MaxValue 1000
int main()
{
//输入数据
int n,m;
int low = 0;high;
int key;
int result;
int NUM[MaxValue];
scanf("%d",&n);
for (int i=0;i<n;i++)
{
scanf("%d",&NUM[i]);
}
scanf("%d",&key);
high = n-1;
while(high>=low)
{
int mid = (low+high)/2;
//通过已输入数据实现非递归查找
if(key == NUM[mid])
{
result = NUM[mid];
printf("%d",result);
}
else if(key<NUM[mid])
{
low = mid + 1;
}
else if(key>NUM[mid])
{
high = mid-1;
}
else
printf("无可用数值");
}
//返回数据
return 0;
}
递归方式
int BinarySearch(int A[],int start,int end,int target)
{
int mid;
if(start>end)
{
return NULL ;
}
else
{
mid = (start + end) /2;
if(target == A[mid])
{
return mid;
}
else if(target > A[mid])
{
BinarySearch(A,mid+1,end,target);
}
else(target < A[mid])
{
BinarySearch(A,start,mid,target);
}
}
}
全排列问题(例题)
问题描述:有1->n个数字,请问有多少种排列方式?
自我思想分析:将N个数拆分成每一个只有1个元素的数组,然后每一个数字都有多种排列情况,然后将每一个部分解合并为原来问题的解。
//通过递归求解全排列
# include<stdio.h>
#define MaxValue 1000
int main()
{
//读取数据
//采用递归方法求解
//伪代码
int DG(int A[],int num)
{
if(判断目前的可变元素是否只有一个)
{return 1;}
else
{
int result;
for(i->n,)
{遍历第一层可能出现的所有结果};
result = 所有结果数;
result +=DG(从排除固定的第一个数字开始再次将后面元素进行全排列)
}
return result;
}
** 全排列递归问题的思想就是将每一个数与想要交换的数字进行交换以后,其后面的组合必须再次循环一遍进行交换,这样才能满足全部都能够考虑到。然后在最后只剩一个数字的时候,没法交换了,我们才将总体组合的系数加一,然后输出这个组合**
//递归全排列问题
# include <stdio.h>
#define MaxValue 10000
//实现交换
void swap(int a,int b)
{
int temp = a;
a = b;
b = a;
}
//实现输出序列的每次组合并且将cout计数++
int ArrayCount(int A[],int n-1)
{
for (int i=0;i<=n-1;i++)
{
printf(A[i]);
}
cout++;
}
//递归实现算法(已经了解)
DG(int A[],int q,int n)//q表示从第几个元素开始全排列,n表示所有数列的总项
{
if(q==n)//已经到达最后一个元素的位置
{
return ArrayCount(A[],n-1);
}
else
{
for(int i=q;i<n;i++)
{
swap(A[i],A[q]);
DF(A[i],q+1,n);
swap(A[i],A[q]);
}
}
}
int main()
{
//读入数据
int A [MaxWalue]={0};
int num ,result;
for (int i=0;i<num;i++)
{
scanf("%d",&A[i]);
}
//实现全排列
result = DF(A,0,num);
printf(result);
return 0;
}
整数划分问题(例题)
问题描述:
n=m1+…+mi(1<=mi<=n),则称为{m1,…,mi}的n的一个划分
如果{m1,…,mi}中最大值不超过m,及max{m1,m2,…,mi}<=m,我们称这是一个属于n的m划分。我们记n的m划分的个数f(n,m).
**已经理解:**可以通过思维导图理解
整数划分的代码:
# include <stdio.h>
int Para(int n,int m)
{
if((n<1)||(m<1))
{
return 0;
}
if((n=1))||(m=1))//情况1
{
return 1;
}
else if(n!=m)
{
if(n<m)//情况2
{
return Para(n,n);
}
else (n>m)//情况3+4
{
//存在包含m以及不包含m的情况
return f(n-m,m)+f(n,m-1);
}
}
else (n=m)//情况5+6
{
//存在包含n以及不包含n的情况
return f(n,n-1)+1;
}
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
Para(n,m);
}
归并排序问题(例题)
//分治的思想递归拆分,通过比较每个子序列的数字的大小,然后进行合并操作,不断将子问题合并为原来的大问题,得到解决
void GB(int A[],int B[],int start,int last)
{
//数组只剩下一个元素的时候
if(start >= last)
{
return A[start];
}
else (start<last)
{
int len = last-start;
int mid = (len>>1)+start;
start1 = start;start2=len+1;
end1 = mid;end2=last;
GB(A,B,start1,end1);
GB(A,B,start2,end2);
int i = start;
//排序
while((start1<=end1)&&(start2<=end2))
{
B[i++]=A[start1]<A[start2]?A[start1++]:A[start2++];
}
//有剩余
//左侧剩余
while(start1<=end1)
{
B[k++]=A[start1++];
}
while(start2<end)
{
B[k++] = A[start2++];
}
for(i=start;i<last;i++)
{
A[i] = B[i];
}
}
}