【解題報告】openjudge Freda的越野跑 資料結構與演算法mooc 內排序
阿新 • • 發佈:2019-02-19
描述
Freda報名參加了學校的越野跑。越野跑共有N人蔘加,在一條筆直的道路上進行。這N個人在起點處站成一列,相鄰兩個人之間保持一定的間距。比賽開始後,這N個人同時沿著道路向相同的方向跑去。換句話說,這N個人可以看作x軸上的N個點,在比賽開始後,它們同時向x軸正方向移動。
假設越野跑的距離足夠遠,這N個人的速度各不相同且保持勻速運動,那麼會有多少對參賽者之間發生“趕超”的事件呢?
輸入
第一行1個整數N。
第二行為N 個非負整數,按從前到後的順序給出每個人的跑步速度。
對於50%的資料,2<=N<=1000。
對於100%的資料,2<=N<=100000。
輸出
一個整數,表示有多少對參賽者之間發生趕超事件。
樣例輸入
5
1 3 10 8 5
樣例輸出
7
原題連結:http://dsalgo.openjudge.cn/huawen10/1/
解題思路:
其實這個超過的過程, 就是在模擬基於比較的排序的交換過程,也就是說我們需要做的是記錄排序過程中的交換次數。(最直觀的就是氣泡排序,速度快的就換到前邊,換一次就是超過一個人)
注意到相同速度的人後邊的不會超過前邊的,因此需要一個穩定的排序演算法,然後資料範圍的限制我們要用O(nlogn)的,那麼也就很自然的取選用歸併排序了。
需要記錄的交換髮生在merge左右兩個子列的時候,如果在左子列還有剩餘的時候先排入一個由子列中的元素的話,就相當於這個右子列的元素超過了左子列裡的剩餘元素。 就是需要記錄這個東西。
哦還有小trick是ans要開到long long int,不然應該是會…WA?
以下程式碼:
#include <iostream>
using namespace std;
int a[100001];
int ta[100001];
long long int ans = 0;
void merge(int left, int right, int middle)
{
int i, j, index1, index2;
for (j = left; j <= right; ++j)
ta[j] = a[j];
index1 = left;
index2 = middle + 1;
i = left;
while (index1 <= middle && index2 <= right)
{
if (ta[index1] >= ta[index2])
{
a[i] = ta[index1];
++i;
++index1;
}
else
{
a[i] = ta[index2];
ans += middle - index1 + 1; //這個右子列元素超過了左子列中剩餘的元素
++i;
++index2;
}
}
while (index1 <= middle)
{
a[i] = ta[index1];
++i;
++index1;
}
while (index2 <= right)
{
a[i] = ta[index2];
++i;
++index2;
}
}
void mergesort(int left, int right)
{
int middle;
if (left < right)
{
middle = (left + right) / 2;
mergesort(left, middle);
mergesort(middle + 1, right);
merge(left, right, middle);
}
}
int main()
{
int n;
cin >> n;
for (int i = 0; i < n; ++i)
{
scanf("%d", &a[i]);
}
mergesort(0, n - 1);
cout << ans;
//system("pause");
return 0;
}