2020.10.6 清北学堂 J2综合强化营 D6 分治笔记

分治

\(1\).定义

“分而治之”,即把大问题拆成一个个的小问题,然后分别解决这些小问题,最终求得答案。

\(2\).应用

\(\text{Example}\)
把一个长度 \(N\) 的数组从小到大排序

\(\text{Solution}\)

\(\text{Quick Sort}\ \to\) 分成两个小数组,保证左子数组例的数均小于右子数组,不断重复上述过程,完成排序

\(\text{Merge Sort}\ \to\) 分成两个较小的数组,对左子数组进行排序,对右子数组进行排序,最终合并成一个较大的数组,不断重复上述过程,完成排序

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++];
}

\(\text{Example 2}\)

一共有 \(n\) 片芯片,芯片有好有坏。我们不知道哪个是好芯片,哪个是坏芯片,但保证好芯片比坏芯片多
我们可以用两片芯片互相测试对方是否是好芯片。
已知好芯片一定能返回正确的结果,而坏芯片给出的结果是完全随机的。
我们现在希望能找到一个好芯片

\(\text{Solution 2}\)

分成两组,每组两个比较.
[好坏]或者[坏坏] \(\to\) 把两块芯片都去掉;
如果结果是[好好] \(\to\) 任选其中一块去掉.

剩下 \(1\) 个或 \(2\)\(\to\) 是好芯片

奇数个 \(\to\) 任取一个和其它所有芯片比较,
如果有一半将此芯片判为好芯片 \(\to\) 好芯片
否则 \(\to\) 坏芯片 \(\to\) 去掉

\(\text{Problem 1}\) 求逆序对 \(\to\ \ \text{Merge Sort}\)

\(2\).二分算法

核心 : 把问题缩小为一个原规模 \(\dfrac{1}{2}\) 的子问题

常用 : 最小值最大 \(or\) 最大值最小 \(or\) 满足某条件的最值

\(\text{(1)}\) 二分查找

模板固定,不要混用。——来自 \(\text{lyd}\) 老师的忠告

\(\text{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;
}

\(\text{Problem 2}\)
给出 \(N\) 个月的开销,要求把 \(N\) 个月的开销按顺序划分成 \(M\) 个时间段,计算每一段的开销总和,求 \(M\) 个开销总和中最大值的最小值

\(\text{Solution 2}\)
求值问题 \(\to\) 判定问题
求值:求一个划分方式,(划分区间和的最小值)最小
判定 \((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;
}
posted @ 2020-10-06 20:33  _pwl  阅读(267)  评论(3)    收藏  举报
1 2 3
4