歸併排序 歸併排序的刷題記錄 20 09 25

2022-04-29 03:21:11 字數 3465 閱讀 6939

p1309 瑞士輪

p1626 象棋比賽

void

merge

(ll l, ll r)

p1774 最接近神的人

歸併排序

void

merge

(ll l, ll r)

while

(i <= mid) b[cnt ++

]= a[i ++];

while

(j <= r) b[cnt ++

]= a[j ++];

for(ll i = l; i <= r; i ++

) a[i]

= b[i]

;}

ans +

=(mid - i +1)

;

這句話的意思是,記錄所有移動的總數,而且一定是最少的:

為什麼是mid - i + 1?

首先要明白,歸併排序是每次將當前要處理的序列分兩半,

我們將 左邊從l到 mid 的指標為 i, 右邊 從 mid + 1 到 r的指標叫 j;

每當我們找到乙個要交換位置的 比i小 和 j 的時候,都要將 j 這個位置的數移到 i位置之前,

這其中越過的數就包括了 i , 於是要 mid - i + 1 中的 +1 ;

而且,每次我們處理前的這個序列,其左半邊與右半邊的數一定是從小到大排好的,

而每一次將後半部分移動到前面之後,接下來 j 的位置一定是緊貼著 mid 的,

而 j上的數的終點就是 i這個位置的前面,這就是mid - i + 1 中的 mid - i 的由來;

綜合起來就是 每找到乙個需要往前走的 j 上的數 ,其向前交換的步數就是 mid - i + 1;

#include

using

namespace std;

typedef

long

long ll;

const

int n =

5e5+

10, m =10;

ll a[n]

, b[n]

;ll n;

ll ans =0;

void

merge

(ll l, ll r)

while

(i <= mid) b[cnt ++

]= a[i ++];

while

(j <= r) b[cnt ++

]= a[j ++];

for(ll i = l; i <= r; i ++

) a[i]

= b[i];}

intmain()

/* _

/\    ∠ \

/ |   / / _

| z ____∠ /  / ヽ

/     ヽ\  / 〉

|     ` / / /

\ ● ` ● * 〈 /

(() () / \ \

-` - ィ  | //

/ /   / / \ \\

\_/  (_/ | //

/       |//

\_ / ̄ ̄`―_丿

*/

p1309 瑞士輪

這道題活用了 二分 和 歸併 的思想;

比賽前的分數是已經(手動)排好了的,而且比賽的原則是每兩個相鄰的(1和2 , 3和4……)比賽;

也就是說,從一開始所有選手就已經分成了兩兩一組的情況,且保證後面的組裡面的選手的分數必定大於前面所有的組裡面的選手;

那麼就讓贏的人一組,輸的人一組的;

操作完成後兩組是必定從小到大排好序的;

而這道題會改變的值也只有選手進行一場比賽之後的分數,

而改變只是每兩個人之間發生的,所以需要改變的順序很少很少,用歸併再適合不過了!

(如果想要每輪下來都快排一次的勸退,因為快排的話每次二分都要改變不少的值,浪費時間)

……分完之後直接 重新排序並替換 就可以了;

#include

using

namespace std;

typedef

long

long ll;

const

int n =

2e5+

10, m =10;

int n, r, q;

int a[n]

;int win[n]

, lose[n]

;int s[n]

, w[n]

;bool

cmp(

int x,

int y)

intmerge()

intmain()

else

merge()

;}cout << a[q]

;return0;

}/*_

/\    ∠ \

/ |   / / _

| z ____∠ /  / ヽ

/     ヽ\  / 〉

|     ` / / /

\ ● ` ● * 〈 /

(() () / \ \

-` - ィ  | //

/ /   / / \ \\

\_/  (_/ | //

/       |//

\_ / ̄ ̄`―_丿

*/

p1626 象棋比賽

這道題題目好繞……

總的來說就是要你先排個序,然後記錄每兩個相鄰的數的差cha;

然後 輸出 cha[i ~ k] 的總和;

p:為什麼用 歸併呢?

s:可以不用啊。

p:……

s:正解:

其實歸併相對於快排要優秀一些

1.時間穩定(快排的複雜度下限nlogn,上限 n2 很容易被卡,而歸併固定nlogn)

2.排序穩定(快排不穩定)(穩定指同樣大小的數排序完之後是否按讀入的先後順序輸出)

歸併思路:分治,將原串拆半,然後將這兩半排序(遞迴),再開乙個臨時陣列,依次將兩個陣列的最小值加入這個臨時陣列,最後複製回原陣列

#include

using

namespace std;

typedef

long

long ll;

const

int n =

2e5+

10, m =10;

int a[n]

, b[n]

;void

merge

(int l,

int r)

intmain()

dummy

歸併排序(2 路歸併排序)

遞迴寫法 include define maxn 100 void merge int a,int l1,int r1,int l2,int r2 將陣列a的區間 l1,r1 和區間 l2,r2 合併為乙個有序區間 else while i r1 while j r2 for int i 0 i非遞...

python歸併排序 python 歸併排序

排序思路 1.將陣列分成兩組a,b,建立臨時陣列 c,c長度 a b 2.i,j分別屬於a,b 3.若a i b j 將b j 放入c,j 否則 a i 放入c,i 4.迴圈3步驟,將a或b中剩餘的元素放入c,再將c複製到陣列中 5.遞迴3 4直到a,b序列的長度 1 歸併排序 class merg...

歸併排序以及歸併排序的優化

1 歸併排序的實現 歸併排序也利用了分治法的思想,首先將序列分成左右兩部分,將左右兩部分分別排序,然後將有序的兩個子串行進行合併 即merge操作 程式是遞迴進行的,主函式實現如下 歸併排序主函式 void merge sort int a,int first,int last else while...