「TPS」:修訂間差異

出自TFcisWiki
跳至導覽 跳至搜尋
行 364: 行 364:
範例輸入輸出必須與[[#產測資|產測資]]中設定的範例測資相同。
範例輸入輸出必須與[[#產測資|產測資]]中設定的範例測資相同。


{{TOJ side box
|628|B. 國中會考分
}}
如果有多筆範例測資,標題應改命名為「範例輸入1、範例輸出1、範例輸入2、範例輸出2」等。
如果有多筆範例測資,標題應改命名為「範例輸入1、範例輸出1、範例輸入2、範例輸出2」等。
{{clear}}


{{TOJ side box
|631|E. 蓋歐格(單個範例附說明)
|632|F. 最小生成數(多個範例,僅有 1 個範例有說明)
|637|D. 本田小狼(有圖片的範例說明)
}}
如果有需要說明測資,可加上「範例說明」章節,詳細說明範例測資中的意義,亦可附圖說明。
如果有需要說明測資,可加上「範例說明」章節,詳細說明範例測資中的意義,亦可附圖說明。



於 2022年8月17日 (三) 22:37 的修訂

TPS(Task Preparation System)是一套可以方便產生題目測試資料以及題本的工具,關於 TPS 可以參考以下的 GitHub Repo:

資料夾結構

根目錄

資料夾或檔案 說明
.github/workflows/ Github 自動化流程設定檔
pA/ 題目A
pB/ 題目A
Makefile 檔案:Icon tools.svg 匯入 CMS 的指令
README.md
cover.tex 題本封面
template.tex 題本內文模板,不需修改

題目目錄

資料夾或檔案 說明
attachments/ CMS 題目敘述頁的附件,通常僅會在第一題的附件放置合併題本。
gen/ 產測資程式
scripts/ TPS scripts,不需修改
solution/ 標程
statement/ 題目敘述
tests/ 測資檔
validator/ 驗測資程式
problem.json 競賽名稱題目名稱題目英文名稱題目編號記憶體限制時間限制
solutions-check.txt 所有標程的執行結果報告
solutions.json 標程產測資指定的標程
subtasks.json 子任務、使用的驗測資程式
本頁面主要使用 TNFSH-Programming-Contest/cms-environment-testing-problem[1] 的 pB[2] 作為範本。

參考資料

事前準備

建立GitHub Repo

  1. 進入 tps-starter。[1]
  2. 點擊 Use this template。[2]
  3. 填寫Repo資訊
    • Repository name 填入競賽英文名,例如「cms-environment-testing-problem」。
    • Description 填入競賽中文名,例如「CMS環境測試題目通用版」。
    • 檔案:OOjs UI icon alert-destructive.svg 注意:可見度必須選擇 Private
    • 點擊 Create repository from template。

參考資料

建立題目資料夾

此操作在每個競賽通常僅需執行 1 次。

  1. 進入由 tps-starter 建立的 GitHub repo。
  2. 點擊 Actions。
  3. 在 Workflows 段落,點擊 New problem。[1]
  4. 點擊 Run workflow,在 How many problems in this contest? 輸入要建立的題目數量。
    • 如果已有 3 題,要再新增 1 題,直接輸入 4 即可,已建立的目錄會直接被略過。
  5. 點擊藍色 Run workflow 按鈕。
  6. 等待題目目錄建立完成,約 1 分鐘。

參考資料

操作方式

檔案:Icon tools.svg 以下有此標誌的說明需要 CMS 系統管理員操作,出題者可忽略此說明。

競賽名稱

競賽名稱使用於:

  1. CMS 參賽介面左上角。
  2. 題本封面第一行。
  3. 題本內文各頁的左上角。

需寫入於:(範例為「CMS環境測試題目通用版 v1.1」)

  1. cover.tex。[1]
  2. 各題目 problem.json[2] 的 contest_name 欄位。
  3. 檔案:Icon tools.svg CMS 管理系統的 Description 欄位。

參考資料

題目名稱

題目名稱使用於:

  1. CMS 競賽概況的題目列表。
  2. CMS 題目敘述頁面。
  3. 題目標題(第一頁第一行)。
  4. 該題目各頁右上角。

需寫入於 problem.json[1] 的 title 欄位,範例為「Piñata」。

參考資料

題目英文名稱

題目英文名稱應足以讓所有命題人員識別個別題目即可,通常取自於中文題目名稱,並盡量僅使用一個英文詞,首字大寫,若需要兩個英文詞以上,則使用PascalCase。使用於:

  1. CMS 競賽概況的題目列表。
  2. CMS 題目敘述。
  3. CMS 系統內部用來識別題目的 Primary key
    • 檔案:Icon tools.svg 由於同一 CMS 系統上的名稱無法重複,若與其他競賽題目衝突[1],建議加上競賽名稱的英文縮寫作為前綴(例如「2022P-」)。
  4. 可能作為 GitHub repo 內的題目資料夾名稱。

需寫入於 problem.json[2] 的 name 欄位,範例為「Pinata」。

參考資料

題目編號

題目編號為 A, B, C... 的流水號,在決定題目順序後才會確定,使用於:(範例為「B」)

  1. CMS 競賽概況的題目列表。
  2. 題目標題(第一頁第一行)。
  3. 該題目各頁右上角。
  4. 該題目各頁頁碼處。

記憶體限制

需寫入於 problem.json[1] 的 memory_limit 欄位,單位為MB,範例為「512」MB。

參考資料

時間限制

需寫入於 problem.json[1] 的 time_limit 欄位,單位為秒,範例為「1.0」秒。

參考資料

標程

AC code(官方解法、標程等)需放置在 solution[1] 資料夾內,檔名無限制。同時將該檔名寫入 solutions.json[2] ,格式請參照範本,verdict 必須標記為 model_solution,範例檔名為「ac.cpp」[3]

其他 AC code 亦按照前述方式操作,verdict 必須標記為 correct。

其他類型的錯誤解法亦按照前述方式操作,verdict 標記方式請參考官方說明[4]及 tps script[5]

參考資料

產測資

TPS 產測資方式與 Codeforces polygon 相同。測資可以使用手產測資檔案,亦可由程式亂數產生,亦可混合兩者。

手產測資檔

最佳實踐:
  1. 僅在範例測資和 edge case 使用手產測資檔,其他使用產測程式。
  2. 在 gen/manual 保存與題本相同的範例測資。

手產測資檔應放置在 gen/manual 資料夾[1]內,檔名無限制,但建議副檔名為 .in。

本範例包含一個固定測資檔 sample-01.in[2] 作為範例測資。

參考資料

產測資程式

重要:產測資程式必須
  1. 使用命令列參數讀入測資組及測資點[1][2]
  2. 使用標準輸出(stdout),不可直接寫入檔案。
  3. 執行一次僅輸出一筆測資。
  4. 使用 testlib.h[3] 等設定亂數種子的方式,使得每次產生的測資都是相同的。

產測資程式應放置在 gen 資料夾[4]內,檔名無限制。‎

以下說明請配合範例檔案 gen/gen.cpp[5]

使用 #include "testlib.h" 引入 testlib 函式庫。

main 函數務必寫成 int main(int argc, char* argv[]) 來接收命令列參數。

在 main 函數的第一行使用 registerGen(argc, argv, 1); 將命令列參數作為亂數種子。

命令列參數會保存在 argv 內,可將其保存在 string 內: string task = argv[1];,或是使用 atoi[6] 等函數轉換為整數。例如範例中第一個參數用來判斷是第幾組測資,將其轉換為 int taskN 用於判斷。若為第一筆測資,測資範圍則為 87,若為其他測資,測資範圍則為 10^9。

使用 rnd.next(-maxN, maxN) 來隨機產生範圍在 -maxN 到 maxN 之間的整數,保存在變數上用於之後輸出。

最後將產生的測資輸出。

注意 注意: 由於 cout 中執行順序屬未定義行為,請勿將多個 rnd.next 合併在一個 cout 中使用,請分開 cout 或事先保存在變數上。

cout << rnd.next (1, n) << endl;
檔案:Yes check.svg
cout << rnd.next (1, n) << " " << rnd.next (1, n) << endl;
檔案:X mark.svg 未定義行為
cout << rnd.next (1, n) << " ";
cout << rnd.next (1, n) << endl;
檔案:Yes check.svg
int a = rnd.next (1, n), b = rnd.next (1, n);
cout << a << " " << b << endl;
檔案:Yes check.svg

完成產測資程式後,編譯成檔名為 gen 的執行檔(在 Windows 上的 gen.exe),在命令列使用:

  • gen 1 會隨機產生 4 個 -87 ~ 87 之間的數字(格式參見題目敘述)
  • gen 2 會隨機產生 4 個 -10^9 ~ 10^9 之間的數字

參考資料

產測資指令

產測資指令應放置在 gen/data[1],以下說明請配合範例。‎

每一個測資點以 @subtask 接測資點代號為開頭,這個測資點代號亦會使用在子任務配分

接下來每個測資點可以有多筆測資,每筆測資可以使用手產測資檔,也可使用產測資程式。

  • 使用手產測資檔則為 manual 接續放在 gen/manual 資料夾內的測資檔名。
  • 使用產測資程式則為呼叫在命令列中的指令。

範例中第一行為 @subtask samples 為範例測資(samples 為固定名稱不可更改),包含一個手動測資檔 sample-01.in[2]

重要:將範例測資作為配分為 0 的第一筆測資點,名稱為 samples。

範例中除了範例測資外,共有 2 個測資點,名稱分別為 small 跟 all。兩個測資點都包含 5 筆自動測資。

注意 注意: 如果呼叫產測程式,但在指令中輸入了兩行一模一樣的內容,那麼這兩個測資就會相同(在設定亂數種子的情況下)。

@subtask small
gen 1
gen 1
gen 1
檔案:X mark.svg 會產生 3 筆相同測資
@subtask small
gen 1 1
gen 1 2
gen 1 3
檔案:Yes check.svg
@subtask small
gen 1 pewfw
gen 1 qrewx
gen 1 xckxk
檔案:Yes check.svg

因此通常會在後面放上隨機文字作為亂數種子的一部分,亦可透過更換亂數種子來重新產生測資,隨機文字可使用線上工具[3]產生。

小技巧:
  1. 透過命令列參數直接控制測資範圍,就不需要在產測資程式碼內判斷測資點。
  2. 發現不良的測資時,透過修改命令列參數的隨機文字來得到一筆新的隨機測資。
  3. 若需要 edge case,使用手產測資檔。

參考資料

驗測資程式

如果你寫了一個程式解題的問題,並準備好了測試資料,那麼你將可能會遇到一個恐怖的經驗:測試資料是無效的!(即測試資料並未符合題目所規定的限制),例如超過了範圍上限、你的圖實際上沒有連通、或是你的圖不是一棵樹……你很可能會有這種經驗,就算是有經驗的出題者也可能有時會出錯(知名案例像是 ACM ICPC World final 2007)。

最佳實踐:撰寫驗測資程式來自動檢查測資範圍及其他條件是否有符合題目的規定,避免測資範圍錯誤。

驗測資程式(又稱 validator)應該放置在 validator 資料夾[1]內,檔名無限制,並將檔名寫入 subtasks.json[2] 的 global_validators 或 subtasks 的 validators。

本範例包含 2 個 validator。

validator.cpp [3] 用來驗證所有測資的範圍是否在 -10^9 ~ 10^9 內,故在 subtasks.json[4] 中設為 global_validators。

validator-small.cpp[5] 僅用來測試第 2 筆測資(index = 1)範圍是否在 -87 ~ 87,在 subtasks.json 中設定為 測資 small 的 validators。

除了檢查範圍以外,readInt 等函數會回傳其數值,可以保存到變數上作進一步檢查,例如檢查陣列數值皆相異,檢查是否是圖、樹或其他資料結構。

更多資訊請參見 Codeforces 上的說明[6]

小提示:驗測資程式僅檢查與解法無關的輸入資料限制,檢查是否 TLE、得部分分數屬於標程的範圍。

參考資料

子任務

子任務設定於 subtasks.json[1],包含各子任務的配分、文字描述、驗測資程式。以下說明請參考範例。

subtasks.json 最外層包含兩個 key:

  • global_validators:在所有測資使用的驗測資程式
  • subtasks:包含所有測資點。

subtasks 是一個 key-value pairs,key 與產測資指令中設定的相同。value 包含以下 key-value pairs:

  • index:流水號,出現在題本內的順序,從 0 開始;samples 必為 0。
  • score:子任務分數;samples 必為 0。
  • text:子任務描述,使用在題目描述內。
  • validators:僅在該子任務使用的驗測資程式

參考資料

題目敘述

題本檔案放置於 statement/index.md。使用 MarkdownXeTeX 語法。

結構由上到下依序為:

  1. 題目圖片
  2. 題目本文
  3. 輸入(說明)
  4. 輸出(說明)
  5. 輸入限制
  6. 子任務
  7. 範例輸入
  8. 範例輸出
  9. 提示

題目圖片

參見題目敘述故事#插圖

題目本文

參見題目敘述故事

輸入及輸出說明

輸入輸出說明必須明確說明參賽者要遵守的格式。

應該以一行敘述測資中的一行所代表的資料,例如:

  • 第一行有 1 個整數,代表接下來的測資數量。
  • 第一行有 2 個整數,代表初始座標。

如果需要在其他地方(輸入說明的其他行、輸入限制、題目本文等)提到該變數,應賦予變數代號,例如:

  • 第一行有 2 個整數 代表點的數量, 代表邊的數量。
  • 第一行有 1 個整數 ,代表有 個人。...(換行)...接下來有 行,每一行有 1 個整數代表該人的分數。
注意:同一個變數代號必須在該題目的任何地方皆相同,大小寫也必須相同。

輸入限制

輸入限制用來告知參賽者測資的數值範圍限制,

原始碼 顯示結果
- $1 \leq N \leq 100$
- $1 \leq M \leq N$
- $Y - X$ 必定為 2 個倍數
- 若 $A = 1$,則 $B > 0$
  • 必定為 2 個倍數
  • ,則

子任務說明

參見子任務的操作,即會自動顯示於題本中。

範例輸入及輸出

範例輸入輸出必須與產測資中設定的範例測資相同。

如果有多筆範例測資,標題應改命名為「範例輸入1、範例輸出1、範例輸入2、範例輸出2」等。

如果有需要說明測資,可加上「範例說明」章節,詳細說明範例測資中的意義,亦可附圖說明。

  • 範例輸入
  • 範例輸出
  • 範例輸入1
  • 範例輸出1
  • 範例輸入2
  • 範例輸出2
  • 範例輸入1
  • 範例輸出1
  • 範例說明1
  • 範例輸入2
  • 範例輸出2

提示

如有需要,可以提供一些額外提示。如果內容為解題必須的,不應撰寫於提示,應寫於本文中。

亦可撰寫與解題毫無幫助,但與題目故事相關的小知識。

註解