PAT 乙級 1055.集體照 C++/Java

題目來源html

拍集體照時隊形很重要,這裏對給定的 N 我的 K 排的隊形設計排隊規則以下:ios

  • 每排人數爲 /(向下取整),多出來的人所有站在最後一排;數組

  • 後排全部人的個子都不比前排任何人矮;測試

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

  • 每排其餘人以中間人爲軸,按身高非增序,先右後左交替入隊站在中間人的兩側(例如5人身高爲190、18八、18六、17五、170,則隊形爲17五、18八、190、18六、170。這裏假設你面對拍照者,因此你的左邊是中間人的右邊);設計

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

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

輸入格式:

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

輸出格式:

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

輸入樣例:

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

輸出樣例:

Bob Tom Joe Nick
Ann Mike Eva
Tim Amy John

分析:

第三排:Bob Tom Joe Nick
第二排:Ann Mike Eva
第一排:Tim Amy John

單獨看第三排的人的身高
Bob Tom  Joe  Nick
175 188  190  186

假定最開始他們是有序的
即:190 188 186 175
題目要求的是,最高的在中間,按身高非增序,先右後左交替入隊站在中間人的兩側(這裏的左右,是相對於中間人的左右,即。咱們面對着中間人,對咱們來講就是先左後右
什麼意思呢?
首先,咱們先把最高的放中間,190
接着,先左後右的入隊,下一個 188,變成 188 190
而後,186 入隊, 變成 188 190 186
以此類推能夠獲得:175 188 190 186
稍微分析一下能夠發現這個身高排名規律:
175 188 190 186
no4 no2 no1 no3
(就相似領獎臺的那種,冠亞季軍站旁邊)


假定條件:
t - 用來記錄當前一排的最大值的下標,初始化爲0
m - 當前一排的人數
res - 存放當前一排的人的名字
peoples - 全部人的名字、身高(已排序,高到低)

1. 首先:
 res[m/2] = 身高最高的; // res[m/2] = 190 

2. 遍歷 188 186 175,將 188 和 175 放在 190 的左邊
int j = 0;
for (int i = t + 1; i < m + t; i += 2) {
    res[j++] = peoples[i].name;
}

 i += 2 就是隔一個取一個

 m + t 就能夠理解爲是一個範圍,每次循環,輸出peoples數組 [ t, m + t)的內容(看後面解析)

 i = t + 1 此時 t = 0,即從 peoples[1]開始,隔一個取一個(peoples[0]已經放到了中間)

第一行是 m = 4, t = 0, 那麼這一排的人在peoples中的下標就是 [ 0 , 3)

 res 數組變成了 188 175 190

3. 這時候發現,咱們要的是 175 188 190,怎麼辦呢?reverse翻轉
 reverse(res.begin(), res.begin() + j); 

4. 接着咱們來處理 190 的右邊,和第二步是同樣的作法,須要注意的是,執行完第二部以後,另 j += 1 ,由於此時 j == m/2
 for (int i = t + 2; i < m + t; i += 2) { res[j++] = peoples[i].name; } 
 
  這種狀況就不用 reverse 了,由於是按高到低的順序放到右邊的
5. 輸出當前一排(沒啥好說的了,注意格式
6. 更新 row 和 t 的值
   row--; 
   t = m + t 
  理解一下 t = m + t

怎麼理解 t = m + t 

  1. 當 m = 4, t = 0 時:輸出的是  peoples[0] ~ peoples[3] ,更新 t = m + t = 4 + 0 = 4;
  2. 當 m = 3, t = 4 時:輸出的是  peoples[4] ~ peoples[6] ,更新 t = m + t = 3 + 4 = 7;
  3. 當 m = 3, t = 7 時:輸出的是  peoples[7] ~ peoples[9] .....

C++實現:

#include <iostream>
#include <string>
#include<algorithm>
#include <stack>
#include <queue>
#include <unordered_map>
#include <iomanip>
using namespace std;

/*
190、18八、18六、17五、170

-> 17五、18八、190、18六、170
-> no四、no二、no一、no三、no5
*/ typedef struct Person { string name; int height; }Person; bool cmp(Person a, Person b) { if (a.height != b.height) { return a.height > b.height; } else { return a.name < b.name; } } int main() { int K; // 總排數 int N; // 總人數 cin >> N >> K; vector<Person> peoples(N); for (int i = 0; i < N; ++i) { cin >> peoples[i].name >> peoples[i].height; } sort(peoples.begin(), peoples.end(), cmp); int t = 0; int row = K; // 當前是第幾排 int m = 0; // 當前一排的人數 while (row) { if (row == K) { m = N - (K - 1)* N / K; // N÷K是每排的人數 } else { m = N / K; } // 數組都排好序了 // 190, 188, 186, 175, 170, 168, 168, 160, 160, 159 // N = 10, K = 3 // row = 3 // m = N - (K - 1)* N / K // = 10 - (3 - 1) * 10 / 3 // = 10 - 2 * 3 // = 4 最後一排有4我的 vector<string> res(m); //保存目前一排的人的名字 // t = 0, peoples[0]是最大的190,把它放到中間,也就是m/2 res[m / 2] = peoples[t].name; // 接着把188,175放到res[m/2]的左邊(保持順序175 188 res[m/2]),即:隔一個就取一個放到左邊 int j = 0; for (int i = t + 1; i < m + t; i += 2) { res[j++] = peoples[i].name; } reverse(res.begin(), res.begin() + j); // 把186,放到res[m/2]的右邊(保持順序),即:隔一個就取一個放到右邊 j += 1; for (int i = t + 2; i < m + t; i += 2) { res[j++] = peoples[i].name; } // 輸出 cout << res[0]; for (int i = 1; i < m; ++i) { cout << ' ' << res[i]; } cout << endl; t = t + m; row--; } return 0; }

 

 

Java實現:

相關文章
相關標籤/搜索