POJ-排序-归并排序与逆序对
排序:归并排序与逆序对
一、概念
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
时间复杂度:O(nlogn)
二、算法描述
三、逆序对
逆序对问题设 A 为一个有 n 个数字的有序集 (n>1),其中所有数字各不相同。如果存在正整数 i, j 使得 1 ≤ i < j ≤ n 而且 A[i] > A[j],则 A[i], A[j]这个有序对称为 A 的一个逆序对,也称作逆序数。
例如,数组(3,1,4,5,2)的逆序对有(3,1),(3,2),(4,2),(5,2),共4个。
四、归并排序与逆序对
因为在排序的合并过程中是将两组有序数进行比较,所以根据逆序对的定义,在数组下标 i 小于 j 时,如果有 a[i] 大于 a[j] 就可以知道下标 i 后面所有数都与 a[j] 构成逆序数,只需添加一句求和语句即可求出逆序数了;
例题 POJ1804 Brainman
解题思路
最简单的关于逆序对的题目,题目大意是给出一个序列,求最少移动多少步能使它顺序,规定只能相邻移动。
相邻移动的话,假设a,b 相邻,若a<b 交换会增加逆序数,所以最好不要做此交换;若a==b 交换无意义,也不要进行此交换;a>b时,交换会减少逆序,使序列更顺序,所以做交换。
由上可知,所谓的移动只有一种情况,即a>b,且一次移动的结果是逆序减1。假设初始逆序是n,每次移动减1,那么就需要n次移动时序列变为顺序。所以题目转化为直接求序列的逆序便可以了。
AC代码
#include<cstdio>
int a[];//存储数串的数组
int t[];//排好序的数组
int ans;//逆序对数 void merge(int l, int m, int r)//因为起点和终点不变,所以用i,j来表示可变的下标
{
int k = l, i = l, j = m + ;
while (i <= m && j <= r)//分解数组的首元素进行比较,两个数组分别为[l,m][m+1,r]
{
if (a[i] > a[j])//构成逆序对
{
t[k++] = a[j++];//将较小的元素加入排序后的数组,并移动到下一元素
ans = ans + m - i + ;//从i到middle的值都大于a[j],所以逆序对增加m-i+1
}
else
{
t[k++] = a[i++];
}
}
while (i <= m) t[k++] = a[i++];//若左边还有剩下的
while (j <= r) t[k++] = a[j++];
for (i = l; i <= r; i++)a[i] = t[i];//更新原数组为合并后的数组
} void mergeSort(int l,int r)//归排
{
if (l < r)//递归终止条件
{
int m = (l + r) / ;
mergeSort(l, m);
mergeSort(m + , r);//此时已经通过递归全部拆分
merge(l, m, r);//从单元素开始合并
}
} int main()
{
int T, n, cnt = ;
scanf("%d", &T);
while (T--)
{
ans = ;
scanf("%d", &n);
for (int i = ; i < n; i++)
scanf("%d", &a[i]);
mergeSort(, n - );
printf("Scenario #%d:\n", cnt++);
printf("%d\n\n", ans);
}
return ;
}
例题 POJ2299 Ultra-QuickSort
解题思路
简单直接的归并排序求逆序数,和上一题一模一样。难点是n < 500000,所以答案用int32会WA,要用int64,用long long int也可以,取值范围一样的,printf函数对应I64d和lld。
AC代码
#include<cstdio>
const int N = ;
int a[N];
int t[N];
__int64 ans; void merge(int l, int m, int r)
{
int k = l, i = l, j = m + ;
while (i <= m && j <= r)
{
if (a[i] > a[j])
{
t[k++] = a[j++];
ans += m - i + ;
}
else
{
t[k++] = a[i++];
}
}
while (i <= m)t[k++] = a[i++];
while (j <= r)t[k++] = a[j++];
for (int i = l; i <= r; i++)a[i] = t[i];
} void mergeSort(int l, int r)
{
int m = (l + r) / ;
if (l < r)
{
mergeSort(l, m);
mergeSort(m + , r);
merge(l, m, r);
}
} int main()
{
int n;
scanf("%d", &n);
while (n != )
{
ans = ;
for (int i = ; i < n; i++)scanf("%d", &a[i]);
mergeSort(, n-);
printf("%I64d\n", ans);
scanf("%d", &n);
}
return ;
}
AC代码
POJ-排序-归并排序与逆序对的更多相关文章
- 归并排序求逆序对(poj 2299)
归并排序求逆序对 题目大意 给你多个序列,让你求出每个序列中逆序对的数量. 输入:每组数据以一个数 n 开头,以下n行,每行一个数字,代表这个序列: 输出:对于输出对应该组数据的逆序对的数量: 顺便在 ...
- hihoCoder_二分·归并排序之逆序对
一.题目 题目1 : 二分·归并排序之逆序对 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描写叙述 在上一回.上上回以及上上上回里我们知道Nettle在玩<艦これ&g ...
- 归并排序&&归并排序求逆序对
归并排序 归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序 ...
- 【BZOJ4769】超级贞鱼 归并排序求逆序对
[BZOJ4769]超级贞鱼 Description 马达加斯加贞鱼是一种神奇的双脚贞鱼,它们把自己的智慧写在脚上——每只贞鱼的左脚和右脚上各有一个数.有一天,K只贞鱼兴致来潮,排成一列,从左到右第i ...
- 归并排序+归并排序求逆序对(例题P1908)
归并排序(merge sort) 顾名思义,这是一种排序算法,时间复杂度为O(nlogn),时间复杂度上和快排一样 归并排序是分治思想的应用,我们先将n个数不断地二分,最后得到n个长度为1的区间,显然 ...
- 2014 HDU多校弟五场A题 【归并排序求逆序对】
这题是2Y,第一次WA贡献给了没有long long 的答案QAQ 题意不难理解,解题方法不难. 先用归并排序求出原串中逆序对的个数然后拿来减去k即可,如果答案小于0,则取0 学习了归并排序求逆序对的 ...
- poj2299(归并排序求逆序对)
题目链接:https://vjudge.net/problem/POJ-2299 题意:给定一个序列,每次只能交换邻近的两个元素,问要交换多少次才能使序列按升序排列. 思路:本质就是求逆序对.我们用归 ...
- 归并排序(归并排序求逆序对数)--16--归并排序--Leetcode面试题51.数组中的逆序对
面试题51. 数组中的逆序对 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1: 输入: [7,5,6,4] 输出 ...
- 浙江工商大学15年校赛I题 Inversion 【归并排序求逆序对】
Inversion Time Limit 1s Memory Limit 131072KB Judge Program Standard Ratio(Solve/Submit) 15.00%(3/20 ...
随机推荐
- react navite 学习资料
react 学习资料 https://github.com/crazycodeboy/GitHubPopular crazycodeboy/GitHubPopular https://github.c ...
- Codeforces Round #552 (Div. 3)-C-Gourmet Cat
http://codeforces.com/contest/1154/problem/C 题意: 有一只猫,周一周四周日吃鱼肉,周二周六吃兔肉,周三周五吃鸡肉,现给出三种肉的数量,问最多能吃多少天? ...
- (10)树莓派 vim编辑器使用
进去后 1点击 insert 插入数据 2 ctrl+alt+c 粘贴内容 或者 手动敲入代码 3 ctrl+v 保存 4 :wq 保存退出 5 回车
- 鸿蒙OS与微内核
目前主流面向个人端操作系统都不是像鸿蒙一样采用微内核的,或许在这些操作系统上诞生时面对的需求场景用微内核是行不通的.但在当前场景下是不是能走通要实际验证才知道.面对当前操作系统已成熟的市场生态.专利技 ...
- 【JZOJ6246】【20190627】B
题目 求逆续对个数为\(k\)的\(n\)阶排列个数\(mod \ 1e9+7\) $1 \le n , k \le 10^5 $ 题解 $f_{i,j} = \sum_{k=0}^{i-1} f ...
- 【CF241E】Flights
[CF241E]Flights 题面 洛谷 题解 对于原来的图,如果一条边不出现在\(1\)到\(n\)的路径上面,直接\(ban\)掉即可. 那么考虑一条边\(u\rightarrow v\),一定 ...
- 一篇文章把你带入到JavaScript中的闭包与高级函数
在JavaScript中,函数是一等公民.JavaScript是一门面向对象的编程语言,但是同时也有很多函数式编程的特性,如Lambda表达式,闭包,高阶函数等,函数式编程时一种编程范式. funct ...
- shell 命令行参数(基本)
命令行参数 $0 表示程序名.$1 至 \$9则是位置参数.$# 表示参数的个数.$* 将所有参数当做一个整体来引用$@ 把每个参数作为一个字符串返回,可以使用for循环来遍历$? 最近一个执行的命令 ...
- GC(一)内存管理与垃圾回收
参考文章: 内存分配.GC原理与垃圾收集器:http://www.importnew.com/23035.html g1垃圾回收器:http://blog.jobbole.com/109170/ cm ...
- SVN提示is already locked 解决办法
当svn提示is already locked ,反复clean up也无用, 可以在cmd下进入到目标文件夹的目录 执行svn cleanup 等待执行成功,就可以update了