演算法1:求逆序對數與顯著逆序對數(歸併排序)
阿新 • • 發佈:2019-01-10
寫在前面:由本文開始記錄本人的演算法刷題之路,日後會不定期更新,歡迎討論!本系列系本人原創,如需轉載或引用,請註明原作者及文章出處。
求逆序對數問題是歸併排序的基礎問題,顯著逆序對數則是逆序對數的升級版。POJ2299,POJ1804均是此類問題(但是個別細節不同,例如POJ2299需要將逆序對數變數num設為long long int型)。 一、求逆序對數 描述 對於一個長度為N的整數序列A,滿足i < j 且 Ai > Aj的數對(i,j)稱為整數序列A的一個逆序。請求出整數序列A的所有逆序對個數
輸入 輸入包含多組測試資料,每組測試資料有兩行
第一行為整數N(1 <= N <= 20000),當輸入0時結束
第二行為N個整數,表示長為N的整數序列
輸出
每組資料對應一行,輸出逆序對的個數
樣例輸入51 2 3 4 555 4 3 2 1110樣例輸出0100解體思路
輸入 輸入包含多組測試資料,每組測試資料有兩行
第一行為整數N(1 <= N <= 20000),當輸入0時結束
第二行為N個整數,表示長為N的整數序列 輸出 每組資料對應一行,輸出顯著逆序對的個數 樣例輸入51 2 3 4 555 4 3 2 1612 10 8 6 4 20樣例輸出046
解體思路 與求逆序對數不同,由於Ai > 2 * Aj,因此需要將排序和計數分別操作。也就是先做count,再做merge。
程式碼
求逆序對數問題是歸併排序的基礎問題,顯著逆序對數則是逆序對數的升級版。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的整數序列A,滿足i < j 且 Ai > 2 * Aj的數對(i,j)稱為整數序列A的一個顯著逆序。請求出整數序列A的所有顯著逆序對個數#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(1 <= N <= 20000),當輸入0時結束
第二行為N個整數,表示長為N的整數序列 輸出 每組資料對應一行,輸出顯著逆序對的個數 樣例輸入51 2 3 4 555 4 3 2 1612 10 8 6 4 20樣例輸出046
解體思路 與求逆序對數不同,由於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;
}