当前位置: 首页 > news >正文

分治算法

本文代码适用于c++

引入

现在来了一队女生共n人,但是我们得知其中有一位是小南娘。我们如何快速找到那位小南娘呢?

每次查询一个队列我们可以得到该队列中是否存在南娘。

不难想到,我们可以将这n人均分成两组,然后再将含有小南娘的那一组继续均分......直到最小的组只有一人。这样时间复杂度为O(log n)。

在解决上面查小南娘的问题中我们正是使用了分治的思想。分治算法的要点在于【拆】:如何将问题拆分为小问题;【合】:将小问题的解合并为最终问题的解。

下面我们看几个典型的例子。

归并排序

给定一个数列a,将它排序。

分析

考虑如何【拆】【合】

  1. 【拆】:不难想到,只需将数列分成几个小数列分别排序即可。当数列只有一元时它就天然有序。
  2. 【合】:如何将两个有序的数列合并成一个有序的数列呢?我们可以用双指针轻松解决

双指针即定义两个指针i,j。
对于两个有序数列a,b:
(不妨两者都是从小到大)
初始令i=j=1(i,j分别用来访问a,b)
每次操作将ai,bj中较小的一项加入数列c,并且让最小一项对应的指针加一。
这样经过|a|+|b|次操作,我们就可以将两个有序数列合并为新的有序数列

代码实现

#include <iostream>
#include <cstdio>
using namespace std;long long n, cnt = 0;
long long a[500005];
long long tmp[500005];void merge(int l, int mid, int r)
{int i = l, j = mid + 1, k = l;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++];for (int m = l; m <= r; m++) a[m] = tmp[m];
}void doit(int l, int r)
{if (l >= r) return; // 递归终止条件(单个元素无需排序)int mid = (l + r) / 2;doit(l, mid);       // 排序左子数组(l~mid)doit(mid + 1, r);   // 排序右子数组(mid+1~r)merge(l, mid, r);   // 合并两个有序子数组
}int main()
{cin >> n;for (int i = 1; i <= n; i++){scanf("%lld", &a[i]);}doit(1, n);for (int i = 1; i <= n; i++) {cout << a[i] << " ";}return 0;
}

逆序对

问题

给定数列a,求满足i>j,ai<aj的(i,j)个数。

分析

  1. 【拆】 [l,r]拆分为[l,mid]和[mid+1,r]。当区间长度为1时没有逆序对。
  2. 【合】 [l,r]中的逆序对无非三种:
    (1) i,j都在[l,mid]中
    (2) i, j都在[mid+1,r]中
    (3) i,j分别在两个区间中

问题在于如何求解(3)类中的逆序对个数。

由于每个子区间中的逆序对个数已经确定,其内部的序已经不重要,我们可以将子区间内部进行排序,然后通过双指针的方法解决。

代码实现

#include <iostream>
#include <cstdio>
using namespace std;long long n, cnt = 0;
long long a[500005];
long long tmp[500005];void merge(int l, int mid, int r)
{int i = l, j = mid + 1, k = l;while (i <= mid && j <= r){if (a[i] <= a[j]){tmp[k++] = a[i++];}else{// 左子数组剩余元素都与a[j]构成逆序对cnt += mid - i + 1;tmp[k++] = a[j++];}}while (i <= mid) tmp[k++] = a[i++];while (j <= r) tmp[k++] = a[j++];for (int m = l; m <= r; m++) a[m] = tmp[m];
}void doit(int l, int r)
{if (l >= r) return; // 递归终止条件(单个元素无需排序)int mid = (l + r) / 2;doit(l, mid);       // 排序左子数组(l~mid)doit(mid + 1, r);   // 排序右子数组(mid+1~r)merge(l, mid, r);   // 合并两个有序子数组
}int main()
{cin >> n;for (int i = 1; i <= n; i++){scanf("%lld", &a[i]);}doit(1, n);cout << cnt << endl; // 可选:输出逆序对数量
//	for (int i = 1; i <= n; i++) {
//		cout << a[i] << " ";
//	}return 0;
}
http://www.sczhlp.com/news/207662/

相关文章:

  • 专用硬件神经网络优化技术解析
  • 学习逆向的背景知识(自用)
  • Linux-网络安全私房菜(二)
  • 中国建设银行广东分行网站国家卫生资格考试官网
  • 买域名做网站的坏处WordPress默认模板做的站
  • 网站改版 百度收录网站营销方案设计公司
  • 行业电子网站建设做网站用哪个电脑
  • 太原网站上排名装修培训机构哪家最好
  • 代理网站开发什么是网络营销中最容易出问题的步骤
  • 株洲网站做的好的公司wordpress 配置
  • 福建漳州网站建设费用临沂百度网站建设
  • 河南做网站优化31省份新增本土427 1662
  • 张槎网站制作网站如何看是哪家公司做的
  • 做网站教学建筑公司名字大全20000个
  • 网站代码审计网站空间和云主机
  • 什么样的网站开发比较吃香网站logo图怎么做
  • 淄博市建设监理协会网站做网站必须要有的素材
  • 茶叶红酒网站建设网站的第二域名怎么用
  • 哪里可以做购物网站建立一个网站需要花多少钱
  • 网站建设与管理适合女生学吗如何查看网站跳出率
  • 网站建设尽量蓬莱市住房和规划建设管理局网站
  • 网站开发培训班多少报名费互联网公司全名
  • 做网站怎么注册营业执照淘宝网页版怎么退出登录
  • 郑州市做网站的公高校门户网站建设需要多少钱
  • 可做外贸的网站有哪些天津市网站建设
  • 域名在哪个网站卖好营销型网站概念
  • 1个云虚拟主机怎么做多个网站楼市最新消息2022年房价走势
  • 网站开发合作合同wordpress json 登陆
  • nodejs 网站开发网页特效代码下载
  • 寺庙做网站修改wordpress文章id