概述
写在前面:由本文开始记录本人的算法刷题之路,日后会不定期更新,欢迎讨论!本系列系本人原创,如需转载或引用,请注明原作者及文章出处。
求逆序对数问题是归并排序的基础问题,显著逆序对数则是逆序对数的升级版。POJ2299,POJ1804均是此类问题(但是个别细节不同,例如POJ2299需要将逆序对数变量num设为long long int型)。
一、求逆序对数
描述
对于一个长度为N的整数序列A,满足i < j 且 Ai > Aj的数对(i,j)称为整数序列A的一个逆序。请求出整数序列A的所有逆序对个数
输入
输入包含多组测试数据,每组测试数据有两行
第一行为整数N(1 <= N <= 20000),当输入0时结束
第二行为N个整数,表示长为N的整数序列
输出
第一行为整数N(1 <= N <= 20000),当输入0时结束
第二行为N个整数,表示长为N的整数序列
每组数据对应一行,输出逆序对的个数
样例输入
5
1 2 3 4 5
5
5 4 3 2 1
1
1
0
样例输出
0
10
0
解体思路
归并排序,大家看代码自行理解吧。
代码
#include<iostream>
#include<algorithm>
using namespace std;
int n, a[20010], temp[20010], num;
void merge(int begin, int mid, int end)
{
int i = begin;
int j = mid + 1;
int k = begin;
while (i <= mid && j <= end)
{
if (a[i] > a[j])
{
temp[k] = a[j];
k++;
j++;
num += mid - i + 1;
}
else
{
temp[k] = a[i];
k++;
i++;
}
}
while (i <= mid)
{
temp[k] = a[i];
k++;
i++;
}
while (j <= end)
{
temp[k] = a[j];
k++;
j++;
}
for (int p = begin; p <= end; p++)
a[p] = temp[p];
}
void mergesort(int begin, int end)
{
if (begin >= end)
return;
int mid = (begin + end) / 2;
mergesort(begin, mid);
mergesort(mid + 1, end);
merge(begin, mid, end);
}
int main()
{
while (1)
{
cin >> n;
if (n == 0)
break;
for (int i = 0; i < n; i++)
cin >> a[i];
num = 0;
mergesort(0, n - 1);
cout << num << endl;
}
return 0;
}
描述
对于一个长度为N的整数序列A,满足i < j 且 Ai > 2 * Aj的数对(i,j)称为整数序列A的一个显著逆序。请求出整数序列A的所有显著逆序对个数
输入
输入包含多组测试数据,每组测试数据有两行
第一行为整数N(1 <= N <= 20000),当输入0时结束
第二行为N个整数,表示长为N的整数序列
输出
第一行为整数N(1 <= N <= 20000),当输入0时结束
第二行为N个整数,表示长为N的整数序列
每组数据对应一行,输出显著逆序对的个数
样例输入
5
1 2 3 4 5
5
5 4 3 2 1
6
12 10 8 6 4 2
0
样例输出
0
4
6
解体思路
与求逆序对数不同,由于Ai > 2 * Aj,因此需要将排序和计数分别操作。也就是先做count,再做merge。
代码
#include<iostream>
#include<algorithm>
using namespace std;
int n, a[20010], temp[20010], num;
void mcount(int begin, int mid, int end)
{
int i = begin;
int j = mid + 1;
int k = begin;
while (i <= mid && j <= end)
{
if (a[i] > 2 * a[j])
{
num += mid - i + 1;
j++;
}
else
i++;
}
}
void merge(int begin, int mid, int end)
{
int i = begin;
int j = mid + 1;
int k = begin;
while (i <= mid && j <= end)
{
if (a[i] > a[j])
{
temp[k] = a[j];
k++;
j++;
}
else
{
temp[k] = a[i];
k++;
i++;
}
}
while (i <= mid)
{
temp[k] = a[i];
k++;
i++;
}
while (j <= end)
{
temp[k] = a[j];
k++;
j++;
}
for (int p = begin; p <= end; p++)
a[p] = temp[p];
}
void mergesort(int begin, int end)
{
if (begin >= end)
return;
int mid = (begin + end) / 2;
mergesort(begin, mid);
mergesort(mid + 1, end);
mcount(begin, mid, end);
merge(begin, mid, end);
}
int main()
{
while (1)
{
cin >> n;
if (n == 0)
break;
for (int i = 0; i < n; i++)
cin >> a[i];
num = 0;
mergesort(0, n - 1);
cout << num << endl;
}
return 0;
}
最后
以上就是称心睫毛膏为你收集整理的算法1:求逆序对数与显著逆序对数(归并排序)的全部内容,希望文章能够帮你解决算法1:求逆序对数与显著逆序对数(归并排序)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复