1. 程式人生 > >【解題報告】openjudge Freda的越野跑 資料結構與演算法mooc 內排序

【解題報告】openjudge Freda的越野跑 資料結構與演算法mooc 內排序

描述
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; }