# APCS實作題2016年10月第2題:最大和 > 第1版:2023年2月11日 > 第2版:2023年6月9日,加上 C++ 程式碼 > 第3版:2023年10月19日,將程式碼改為更精簡的版本 > 作者:王一哲 > 題目來源:[105年10月29日實作題第2題](https://apcs.csie.ntnu.edu.tw/wp-content/uploads/2020/11/1051029APCSImplementation.pdf) > [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=c295) <br /> ## 題目 ### 問題描述 給定 $N$ 群數字,每群都恰有 $M$ 個正整數。若從每群數字中各選擇一個數字(假設第 $i$ 群所選出數字為 $t_i$),將所選出的 $N$ 個數字加總即可得總和 $S = t_1 + t_2 + \dots + t_N$。請寫程式計算 $S$ 的最大值(最大總和),並判斷各群所選出的數字是否可以整除 $S$。 <br /> ### 輸入格式 第一行有二個正整數 $N$ 和 $M$, $1 \leq N \leq 20$,$1 \leq M \leq 20$。接下來的 $N$ 行,每一行各有 $M$ 個正整數 $x_i$,代表一群整數,數字與數字間有一個空格,且 $1 \leq i \leq M$,以及 $1 \leq x_i \leq 256$。 <br /> ### 輸出格式 第一行輸出最大總和 $S$。 第二行按照被選擇數字所屬群的順序,輸出可以整除 $S$ 的被選擇數字,數字與數字間以一個空格隔開,最後一個數字後無空白;若 $N$ 個被選擇數字都不能整除 $S$,就輸出 $-1$。 <br /> ### 範例一:輸入 ``` 3 2 1 5 6 4 1 1 ``` ### 範例一:正確輸出 ``` 12 6 1 ``` (說明)挑選的數字依序是 5,6,1,總和 $S = 12$。而此三數中可整除 $S$ 的是 6 與 1,6 在第二群,1 在第 3 群所以先輸出 6 再輸出 1。注意,1 雖然也出現在第一群,但它不是第一群中挑出的數字,所以順序是先 6 後 1。 <br /> ### 範例二:輸入 ``` 4 3 6 3 2 2 7 9 4 7 1 9 5 3 ``` ### 範例二:正確輸出 ``` 31 -1 ``` (說明)挑選的數字依序是 6,9,7,9,總和 $S = 31$。而此四數中沒有可整除 $S$ 的,所以第二行輸出 $-1$。 <br /> ### 評分說明 輸入包含若干筆測試資料,每一筆測試資料的執行時間限制(time limit)均為 1 秒,依正確通過測資筆數給分。其中: - 第 1 子題組 20 分:$1 \leq N \leq 20$,$M = 1$。 - 第 2 子題組 30 分:$1 \leq N \leq 20$,$M = 2$。 - 第 3 子題組 50 分:$1 \leq N \leq 20$,$1 \leq M \leq 20$。 <br /><br /> ## Python 程式碼 ```python= ts, ds = [], [] # ts 儲存每群數字中最大的值,ds 儲存 ts 當中可以整除最大和的值 N, M = map(int, input().split()) # 由標準輸入讀取資料行數 N、每行資料筆數 M for _ in range(N): # 讀取 N 行資料 t = max(list(map(int, input().split()))) # 將讀取的資料用空格分隔,轉換成整數格式、組成串列,最後用 max 取出最大值 t #t = max(map(int, input().split())) # 省略 list,寫成這樣也可以 ts.append(t) # 將 t 加到 ts 最後面 S = sum(ts) # 用 sum 計算最大和 S for t in ts: # 由 ts 依序讀取元素存入 t,如果 t 可以整除 S 則加到 ds 最後面 if S%t == 0: ds.append(t) print(S) # 印出最大和 S if not ds: # 若 N 個被選擇數字都不能整除 S 印出 −1 print("-1") else: # 按照被選擇數字所屬群的順序,輸出可以整除 S 的被選擇數字 for i in range(len(ds)): print("{:d}".format(ds[i]), end="\n" if i == len(ds)-1 else " ") ``` <br /> 1. 如果將測料存成 data.txt 並與程式碼 test.py 放在同一個資料夾中,於 Linux 的指令界面可以使用以下指令執行程式,就可以不需要每次執行程式時還需要手動輸入測資。 ```shell python3 test.py < data.txt ``` 如果使用 Windows PowerShell,則要改成以下的指令 ```shell Get-Content data.txt | python test.py ``` 2. 第18行:要注意**最後一筆資料後沒有空格、直接換行**。 6. ZeroJudeg 測試結果,單筆測資費時間久為 20 ms,使用記憶體最多為 3.3 MB,通過測試。 <br /><br /> ## C++ 程式碼 ### 方法1:用 array 儲存讀取的資料 ```cpp= #include <iostream> #include <deque> using namespace std; int main(int argc, char* argv[]) { // 由標準輸入讀取資料行數 N、每行資料個數 M、資料 data int N, M; cin >> N >> M; int data[N][M]; for(int i=0; i<N; i++) { for(int j=0; j<M; j++) { cin >> data[i][j]; } } // 找出每行資料中最大值並儲存到 ts int ts[N] = {0}; for(int i=0; i<N; i++) { for(int j=0; j<M; j++) { if (data[i][j] > ts[i]) ts[i] = data[i][j]; } } // 計算並印出最大和 total int total = 0; for(int i=0; i<N; i++) { total += ts[i]; } cout << total << endl; // 不確定最大和可被幾個數值整除,使用 deque 儲存資料 deque<int> ds; for(int i=0; i<N; i++) { if (total % ts[i] == 0) ds.push_back(ts[i]); } // 如果 ds 是空的印出 -1,否則依序印出 ds 的內容 int len = ds.size(); if (ds.empty()) { cout << "-1" << endl; } else { for(int i=0; i<len; i++) { if (i < (len-1)) cout << ds[i] << " "; else cout << ds[i] << endl; } } return 0; } ``` <br /> 1. 第7 ~ 14行:由標準輸入讀取資料行數 N、每行資料個數 M、資料 data。 2. 第17 ~ 22行:找出每行資料中最大值並儲存到 ts。 3. 第25 ~ 29行:計算並印出最大和 total。 4. 第32 ~ 35行:因為不確定最大和可被 ts 中的幾個數值整除,使用 deque 儲存資料,將可以整除最大和的數值儲存到 ds。 5. 第38 ~ 46行:如果 ds 是空的印出 -1,否則依序印出串列 ds 的資料,特別注意**最後一筆資料後沒有空格、直接換行**。 6. ZeroJudeg 測試結果:花費時間為 3 ms,使用記憶體 336 kB,通過測試。 <br /><br /> ### 方法2:用 vector 儲存讀取的資料,並且合併重複的程式碼 ```cpp= #include <iostream> #include <vector> using namespace std; int main() { // 由標準輸入讀取資料行數 N、每行資料個數 M int N, M; cin >> N >> M; vector<int> ts (N, 0); // ts 儲存每群數字中最大的值,預設為 N 個 0;tmp 暫存讀取的資料,預設為 M 個 0 for(int i=0; i<N; i++) { // 讀取 N 行資料 for(int j=0; j<M; j++) { // 每行 M 筆資料 int t; cin >> t; // 讀取資料並暫存為 t if (t > ts[i]) ts[i] = t; // 依序讀取 M 個數值並存入 t,如果 t 大於 ts[i] 則更新 ts[i] 的值 } } int S = 0; // 最大和 S for(auto t : ts) S += t; // 依序讀取 ts 的內容暫存給 t,再將 t 加到 S 計算最大和 vector<int> ds; // ds 儲存 ts 當中可以整除最大和的值,不確定最大和可被幾個數值整除,使用 vector 儲存資料 for(auto t : ts) { // 依序讀取 ts 的內容暫存給 t,如果 t 可以整除 S,將 t 加到 ds 最後面 if (S%t == 0) ds.push_back(t); } cout << S << endl; // 印出最大和 S if(ds.empty()) { // # 若 N 個被選擇數字都不能整除 S 印出 −1 cout << "-1" << endl; } else { // 按照被選擇數字所屬群的順序,輸出可以整除 S 的被選擇數字 for(auto it = ds.begin(); it != ds.end(); it++) { cout << *it << " \n"[it == ds.end()-1]; } } return 0; } ``` <br /> 基於方法1的程式碼,但是改成使用 vector 儲存讀取的資料,並試著合併重複的程式碼,使程式碼更為精簡。於 ZeroJudeg 測試結果,花費時間為 4 ms,使用記憶體 340 kB,通過測試。 <br /><br /> --- ###### tags:`APCS`、`Python`