1. 程式人生 > 實用技巧 >PTA 1055 集體照

PTA 1055 集體照

拍集體照時隊形很重要,這裡對給定的N個人K排的隊形設計排隊規則如下:

  • 每排人數為/(向下取整),多出來的人全部站在最後一排;

  • 後排所有人的個子都不比前排任何人矮;

  • 每排中最高者站中間(中間位置為/,其中m為該排人數,除法向下取整);

  • 每排其他人以中間人為軸,按身高非增序,先右後左交替入隊站在中間人的兩側(例如5人身高為190、188、186、175、170,則隊形為175、188、190、186、170。這裡假設你面對拍照者,所以你的左邊是中間人的右邊);

  • 若多人身高相同,則按名字的字典序升序排列。這裡保證無重名。

現給定一組拍照人,請編寫程式輸出他們的隊形。

輸入格式:

每個輸入包含 1 個測試用例。每個測試用例第 1 行給出兩個正整數N(≤,總人數)和K(≤,總排數)。隨後N行,每行給出一個人的名字(不包含空格、長度不超過 8 個英文字母)和身高([30, 300] 區間內的整數)。

輸出格式:

輸出拍照的隊形。即K排人名,其間以空格分隔,行末不得有多餘空格。注意:假設你面對拍照者,後排的人輸出在上方,前排輸出在下方.

輸入

Bob Tom Joe Nick
Ann Mike Eva
Tim Amy John

輸出

10 3
Tom 188
Mike 170
Eva 168
Tim 160
Joe 190
Ann 168
Bob 175
Nick 186
Amy 160
John 159

從簡單開始想起:

首先排序。我這裡是從小到大排。

由題目可以知道除了最後一排的每排人數為rs=N/K, 最後一排的個數為lastrs=N/K+N%(N/K)

這意味著 最後一排的物件在陣列中的位置為 N-lastrs+1~N,

    倒數第二排的物件在陣列中的位置為N-lastrs+1-rs~N-lastrs

    倒數第n排的物件在陣列中的位置為 N-lastrs+1-rs*(n-1)~N-lastrs-rs*(n-2)

現在我們已經得到了每行的資料都是啥,接下來就是給每行資料進行重排。

為了將題目簡化,我們可以理解為對於某一行物件從l到r的重排, 物件個數為len=r-l+1

當len為奇數的時候:

黑色筆跡的是題意的思路。從大到小插入,然後輸出, 但是這樣很不方便。

紅色和藍色筆跡是另一種思路。把每一次插入都計數num。當是奇數的時候往藍色部分插入,當是偶數的時候往紅色部分插入。輸出的時候紅色部分直接按照插入的順序輸出,藍色部分需要倒序輸出。

因此我們可以在num為偶數的時候讀到紅色部分就直接輸出,num為奇數的時候存到一個棧裡面,資料讀完後彈出所有的內容。

當len為偶數時:

思路同上。但是紅色部分變為當num為奇數,藍色部分變為num為偶數。

程式碼

 1 #include<iostream>
 2 #include<cstring>
 3 #include<fstream>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 typedef long long ll;
 8 const ll mx=1e4+10;
 9 typedef struct node{
10     string name;
11     ll sg;
12 }STU;
13 STU stu[mx];
14 bool cmp(const STU&a, const STU&b){
15     if(a.sg==b.sg) return a.name>b.name;
16     return a.sg<b.sg;
17 }
18 void paidui(ll l, ll r){
19     stack<string>q;
20     ll num=0, base=(r-l+1)%2==0?1:0;//len 偶數base為1 
21     bool appe=false;
22     for(ll i=l;i<=r;i++){
23         num++;
24         if(num%2==base){//紅色部分 直接輸出
25             if(appe) cout<<" ";
26             appe=true;
27             cout<<stu[i].name; 
28         }
29         else{
30             q.push(stu[i].name);
31         }
32     }
33     while(!q.empty()){//藍色部分 棧彈出使其倒序輸出
34         if(appe) cout<<" ";
35         cout<<q.top();
36         q.pop();
37     }
38     cout<<endl;
39 }
40 int main(){
41     ll N, K;
42     cin>>N>>K;
43     for(ll i=1;i<=N;i++){
44         cin>>stu[i].name>>stu[i].sg;
45     }
46     sort(stu+1, stu+N+1, cmp);
47 
48     ll rs=N/K, lastrs=rs+N%rs;
49     //第一行 最後一排
50     ll d=N-lastrs+1;
51     paidui(d, N);
52 
53     //其他幾行
54     for(ll i=1;i<=K-1;i++){
55         paidui(d-rs*i, d-1-rs*(i-1));
56     }
57 
58     return 0;
59 }