分治
(1).定义
“分而治之”,即把大问题拆成一个个的小问题,然后分别解决这些小问题,最终求得答案。
(2).应用
( ext{Example})
把一个长度 (N) 的数组从小到大排序
( ext{Solution})
( ext{Quick Sort} o) 分成两个小数组,保证左子数组例的数均小于右子数组,不断重复上述过程,完成排序
( ext{Merge Sort} o) 分成两个较小的数组,对左子数组进行排序,对右子数组进行排序,最终合并成一个较大的数组,不断重复上述过程,完成排序
inline void quick_sort(int l,int r){
int mid=a[(l+r)>>1];
int i=l,j=r;
do{
while(a[i]<mid) i++;
while(a[j]>mid) j--;
if(i<=j){
swap(a[i],a[j]);
i++;j--;
}
}while(i<=j);
if(l<j) quick_sort(l,j);
if(i<r) quick_sort(i,r);
}
inline void merge_sort(int l,int r){
int mid=(l+r)>>1;
if(l==r) return;
merge_sort(l,mid);
merge_sort(mid+1,r);
int i=l,j=m+1,k=1;
while(i<=mid && j<=r){
if(a[i]<=a[j]) tmp[k++]=a[i++];
else tmp[k++]=a[j++];
}
while(i<=mid) tmp[k++]=a[i++];
while(j<=r) tmp[k++]=a[j++];
}
( ext{Example 2})
一共有 (n) 片芯片,芯片有好有坏。我们不知道哪个是好芯片,哪个是坏芯片,但保证好芯片比坏芯片多
我们可以用两片芯片互相测试对方是否是好芯片。
已知好芯片一定能返回正确的结果,而坏芯片给出的结果是完全随机的。
我们现在希望能找到一个好芯片
( ext{Solution 2})
分成两组,每组两个比较.
[好坏]或者[坏坏] ( o) 把两块芯片都去掉;
如果结果是[好好] ( o) 任选其中一块去掉.
剩下 (1) 个或 (2) 个 ( o) 是好芯片
奇数个 ( o) 任取一个和其它所有芯片比较,
如果有一半将此芯片判为好芯片 ( o) 好芯片
否则 ( o) 坏芯片 ( o) 去掉
( ext{Problem 1}) 求逆序对 ( o ext{Merge Sort})
(2).二分算法
核心 : 把问题缩小为一个原规模 (dfrac{1}{2}) 的子问题
常用 : 最小值最大 (or) 最大值最小 (or) 满足某条件的最值
( ext{(1)}) 二分查找
模板固定,不要混用。——来自 ( ext{lyd}) 老师的忠告
( ext{Problem} 1)
原问题:一个长度为 (N) 的有序数组 (A) ,查询 (x) 是否在这 (N) 个数中
思路:
令 (m = (l+r) >>1)
按情况分类讨论:
- 若 (A[m] == x),找到 (x) ,返回
- 若 (A[m] > x),故 (A[m]sim A[r]) 中所有的数都大于 (x) ,二分查找 ((l, m))
- 若 (A[m] < x),故 (A[l]sim A[m]) 中所有数都小于 (x) ,二分查找 ((m + 1, r))
inline bool Binary_Search(int x){ // [l,r)
int l=0,r=r-1,m;
while(l<=r){
if(A[m]==x) return true;
else if(A[m]<x) r=m-1;
else l=m+1;
}
return false;
}
( ext{Problem 2})
给出 (N) 个月的开销,要求把 (N) 个月的开销按顺序划分成 (M) 个时间段,计算每一段的开销总和,求 (M) 个开销总和中最大值的最小值
( ext{Solution 2})
求值问题 ( o) 判定问题
求值:求一个划分方式,(划分区间和的最小值)最小
判定 ((x)):是否存在一个判定方式,它划分出的每一段区间的和的最大值 (≤x)
判定问题 ((x)):是否存在一个判定方式,它划分出的每一个区间的和都 (≤x)
inline bool check(int x){
int cnt=0,len=0;
for(int i=1;i<=N;i++){
if(a[i]>x) return false;
if(len+a[i]>x){
len=a[i];
cnt++;
}
else{
len+=a[i];
}
}
return cnt<=M;
}