分治问题特征
(1)平衡子问题:子问题规模大致相同,能把问题划分成大小差不多相等的k个子问题,最好k=2,即分成两个规模相等的子问题。子问题规模相等的处理效率比子问题不等的效率要高
(2)独立子问题 :子问题之间相互独立。这是区别于动态规划算法的基本特征,动态规划算法中子问题是相互联系,不是相互独立的。
特别需要说明的是,分治法不仅能让问题变得容易理解和解决,而且能大大优化算法的复杂度,一般能把O(N)优化到O(log2n)。
这是因为局部的优化有利于全局;
一个子问题的解决,其影响力扩大了k倍,即扩大到了全局
入门:归并排序
归并排序步骤
(1)分解:把原来无序的数列分成两部分,对每个部分,再继续分成更小的两部分
这个过程用递归实现
(2)解决:分解到最后不能再分解,排序
对子序列排序。最低层子序列只包含一个数,不用排序
(3)合并:把每次分开的两部分合并到一起。归并排序的核心操作是合并,其过程类似于交换排序。
而排序一般用stl的sort()排序,不过有些特殊问题可以用归并排序解决
HDU 4911(求最小逆序对).
分析
当k=0时,就是求原始序列中有多少个逆序对
求k=0时的逆序对,不能用暴力法,会TLE
可以用归并思想来解决
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<string>
#include <vector>
using namespace std;
const int MAXN = 100005;
typedef long long ll;
ll a[MAXN], b[MAXN], cnt;
void Merge(ll l, ll mid, ll r) {
//合并函数
ll i = 1, j = mid + 1, t = 0;
while (i <= mid && j <= r) {
if (a[i] > a[j]) {
b[t++] = a[t++];
cnt += mid - i + 1;//记录逆序对的数目
}
else b[t++] = a[i++];
}
//一个子序列中的数据都处理完了,另一个还没有,把剩下的复制过来
while (i <= mid)b[t++] = a[t++];
while (j