歸併排序 洛谷p1039 瑞士輪 的詳解

2021-08-17 12:39:00 字數 1553 閱讀 7501

本蒟蒻做瑞士輪,結果發現了點小技巧,在看瑞士輪之前不妨拿來說一下。

一、cmp函式的小技巧        

大家都知道,乙個陣列sort之後各元素(雖然不是真正意義上的各元素)下標會發生改變。有些題目中在進行一些判斷時會命令值相等時取下標小的(在輸入中出現時間早的),這時候有兩種選擇,一種是用結構體存各個值,這裡講一下另一種:多開幾個陣列。

a用來存序號,v來存值,當然如果有別的條件可以再開其它陣列。我們讓a陣列按v從大到小的順序排,傳入兩個引數x,y作為兩個下標,然後返回v[x]>v[y]即可完成從大到小的排序。這樣做的好處是不會打亂v陣列,因為進行排序的是a陣列,而想訪問v也很容易,v[ a[ i ] ]即可

舉個例子,某題目(不一定是瑞士輪)要求將n個x從大到小排,輸出最大的編號,當x相等時,按y排,y相等時按出現時間早的在前。這時便可如此操作

bool (int x,int y)

return v[x]>v[y];

}

二、瑞士輪的詳解

【題目大意】2*n個選手,每人有初始分與能力值,有r輪比賽,每輪比賽令1 2名對戰、3 4名對戰、5 6名對戰,以此類推。其中每局比賽能力值高者勝,勝者(初始)分值+1,每輪比賽後排名都有可能改變。

【思路介紹】看到此題,最先想到的肯定是for(i~r),每輪sort一遍。但這樣會t,我們不妨再好好想想這道題。這道題每輪後排名可能會變,但只可能是鄰位之間變化,如果每輪都sort,無疑會造成巨大的時間浪費,而歸併排序就非常適合這種小範圍的換位。

確認演算法之後再想想如何將其實現,該題歸併的關鍵是保證記錄名次的陣列降序排列。我們想,在每一輪中,比賽開始前是逆序,結束後勝的人分數都+1,還是逆序,敗的人分數不變,仍然是逆序。讓勝者入win,敗者入lose,這樣每輪win和lose便仍是有序的,所以只需要開兩個陣列,乙個記錄勝者,乙個記錄敗者,在每層for(每一輪比賽)結束時進行合併即可。

合併的複雜度為n(2*n)有r輪就是穩定的n(2*n*r)。

【ac】**及細節解釋

1、win[0],lose[0],num[0]統統都是計數器(反正我下標是從1開始記的,閒著也是閒著)這樣可以幫你省下多達3*4=12個位元組的巨大空間!!!(滑稽)

2、注意一下,選手有n*2個,交了多次才發現

#include#include#includeusing namespace std;

int const maxn=200111;

int num[maxn],v[maxn],ab[maxn],win[maxn],lose[maxn],n,r,q;

bool cmp(int x,int y)

void merge()

while(i<=win[0])

num[++num[0]]=win[i++];

while(j<=lose[0])

num[++num[0]]=lose[j++];

}int main()

else

} merge();

} cout

}

洛谷 P1309 瑞士輪(歸併排序)

在雙人對決的競技性比賽,如桌球 羽毛球 西洋棋中,最常見的賽制是淘汰賽和迴圈賽。前者的特點是比賽場數少,每場都緊張刺激,但偶然性較高。後者的特點是較為公平,偶然性較低,但比賽過程往往十分冗長。本題中介紹的瑞士輪賽制,因最早使用於18951895年在瑞士舉辦的西洋棋比賽而得名。它可以看作是淘汰賽與迴圈...

洛谷P1309 瑞士輪(模擬,歸併排序)

題目描述 2 n名編號為1 2n的選手共進行r輪比賽。每輪比賽開始前,以及所有比賽結束後,都會按照總分從高到低對選手進行一次排名。選手的總分為第一輪開始前的初始分數加上已參加過的所有比賽的得分和。總分相同的,約定編號較小的選手排名靠前。每輪比賽的對陣安排與該輪比賽開始前的排名有關 第1名和第2名 第...

洛谷 P1309 瑞士輪(歸併)

題意 一共2n個人 有乙個初始分數 進行k輪比賽,每輪比賽按當前得分排出名次,然後比賽按照第1名和第2名,第3和第4 第2n 1和2n進行 實力各不相同且實力大的總能獲勝 獲勝方加一分,失敗方分數不變。思路 一開始想在每輪比賽前用sort排序,算了下複雜度大概o n n logn n k 顯然不行。...