TopCoder

User's AC Ratio

NaN% (0/0)

Submission's AC Ratio

NaN% (0/0)

Tags

Description

本題為 Two Steps 題,限用 C++ 作答。你可以在這裡找到範例實作以及範例評分程式,詳細注意事項以及常見問題請參考 Hints。
為配合 TIOJ 格式,本題與 YTP 中使用的格式有些不同。

YTP 團隊正在管理一個擁有 $N$ 台伺服器的樹狀網路拓樸(這棵樹是一個二元樹:以主節點為根時,每個節點最多有 $2$ 個子節點),其中有一台最重要的「主節點(Root)」。小 Y 想把這棵樹的拓樸結構備份到另一個資料中心,但負責搞破壞的小 P 會在傳輸過程中把所有伺服器的編號打亂,讓小 Y 無法直接靠編號認出原本的主節點。

小 Y 必須想辦法把原本的主節點給找出來。

這是一題「通訊互動題」(Communication Problem),而且是其中比較特別的一種。 和一般「自己讀 stdin、算完印到 stdout」的題目不同,互動題裡你不直接處理輸入輸出:你只需要實作題目指定的函式,評測系統會提供它自己的一支程式(grader),在編譯時和你的程式合在一起,並在執行時主動呼叫你的函式、透過參數把資料交給你、再接收你的回傳值。整個互動流程由評測系統掌控,你只要把函式寫對即可。

它的特別之處在於分成兩個階段(Phase 1、Phase 2),你要各實作一個函式。最關鍵的限制是:正式評測時,這兩個階段是兩支完全獨立執行的程式(process),彼此不共享任何全域變數或記憶體狀態——你在 Phase 1 對某個全域變數做的修改,到了 Phase 2 完全不會保留。唯一能從 Phase 1「帶到」Phase 2 的資訊,就是你在 Phase 1 回傳、並由系統一路保存下來的那份顏色標籤。這也正是本題的核心:你必須用顏色把「哪個是主節點」的資訊編碼進去,好讓 Phase 2 在節點編號被完全打亂之後,仍然能夠解讀出主節點是誰。

Phase 1

在第一階段,你會得到這棵樹的完整結構,以及主節點的確切編號 $R$(節點編號從 $1$ 到 $N$)。你可以為樹上的每一個節點指派一個「顏色標籤」,顏色的可用選項只有 $0, 1, 2$ 三種。

為了防止標記過於單一,系統規定:對於任何一種顏色 $c \in {0,1,2}$,被塗成該顏色的節點總數,必須大於或等於 $\lfloor N/D \rfloor$(其中 $D$ 會依子任務而不同:子任務一為 $7$、子任務二為 $3$,詳見下方「子任務」一節)。若你的著色方案違反此規定,將會直接獲得 Wrong Answer

在你完成著色後,請將 $N$ 個節點的顏色透過陣列回傳給系統。

收到你的著色陣列後,系統會將這棵樹的所有節點編號完全隨機打亂(生成一個 $1$ 到 $N$ 的均勻隨機排列)。樹的實體連線結構與每個節點對應的顏色會被完美保留,但你將完全失去原本的節點編號。此外,Phase 2 收到的邊的排列順序、以及每條邊兩個端點的先後順序,也都會被重新隨機打亂,不攜帶任何額外資訊——你只能依靠樹的連線結構與節點上的顏色來判斷主節點。

Phase 2

在第二階段,你會接收到那棵被打亂編號、但帶有你標註顏色的新樹。請根據新樹的連線狀態與節點上的顏色($0, 1,$ 或 $2$),找出在這棵新樹中,哪一個節點才是原本真正的「主節點」,並回傳其新的節點編號

子任務

本題有兩個計分子任務,差別在於 Phase 1 著色的「顏色平衡」要求鬆緊不同(對應範例輸入首行的 D):

  • 子任務一($8$ 分):每種顏色至少要用在 $\lfloor N/7 \rfloor$ 個節點上($D = 7$)。
  • 子任務二($12$ 分):每種顏色至少要用在 $\lfloor N/3 \rfloor$ 個節點上($D = 3$),限制更嚴格。

每個子任務都是全對才給分:必須該子任務內的所有測試資料都回傳正確的主節點,才能拿到該子任務的分數。

本機測試與提交說明

本題接受 C/C++、Python、Java 三種語言。因為這題需要實作「兩個獨立函式」,跟一般讀 stdin、寫 stdout 的題目不太一樣,所以請務必先閱讀這一段,並下載題目附帶的範本套件(public/ 資料夾)。

範例輸入檔案的第一行格式為 N R D,其中 D 是這筆測資的塗色限制參數(7 代表子任務一的 $\lfloor N/7 \rfloor$,3 代表子任務二的 $\lfloor N/3 \rfloor$)。D 由評測系統使用,不會傳遞給你實作的函式。

不論用哪種語言,你都只需要繳交一個檔案,裡面實作以下兩個函式(下面用 C++ 的型別寫,Python/Java 的對應寫法在各自的範本檔案裡):

// Phase 1:給定樹的結構 (N 個節點、邊陣列 u, v) 與主節點編號 R,回傳長度為 N 的顏色陣列
// (colors[i] 對應到編號 (i+1) 的節點;顏色只能是 0, 1, 2)
std::vector<int> assign_colors(int n, int r, std::vector<int> u, std::vector<int> v);

// Phase 2:給定「打亂編號後」的樹結構與顏色陣列,回傳你認為的新主節點編號
int find_root(int n, std::vector<int> u, std::vector<int> v, std::vector<int> colors);

以下為 YTP 原題敘,請注意 TIOJ 上無法繳交 Python 與 Java。

C / C++

繳交檔名為 root.cpp,開頭 #include "lib1513.h"lib1513.h 已經在範本裡,裡面宣告了上面兩個函式,不用自己寫。

本機測試在 public/cpp/ 資料夾下操作:把 root.cpp 換成你的實作,執行 bash compile_cpp.sh 編譯,產生執行檔 root,然後:

./root < ../examples/01.in

本機的 grader 會在同一個 process 裡先跑 Phase 1 再跑 Phase 2,方便 debug。注意:正式評測兩個階段是完全獨立的程式,全域變數不會在兩階段之間保留。

Python

繳交檔名為 root.py,直接在裡面定義 assign_colors(n, r, u, v)find_root(n, u, v, colors) 兩個函式,不需要額外 import。

本機測試把 root.py 放進 public/py/(覆蓋原本的範本檔),然後:

python3 grader.py < ../examples/01.in

Java

繳交檔名為 root.java,需要有 public class root,並在裡面定義兩個非 static 的方法:int[] assign_colors(int n, int r, int[] u, int[] v)int find_root(int n, int[] u, int[] v, int[] colors)

本機測試在 public/java/ 下,把 root.java 換成你的實作後:

bash compile_java.sh
bash run_java.sh < ../examples/01.in

本機測試程式的輸出

執行本機測試程式後,它會印出一行 test: <結果>

  • test: ok:你的實作在這筆範例上通過了——著色合法(陣列大小為 $N$、每個顏色都是 $0/1/2$、且滿足顏色平衡限制),而且 find_root 正確找出了主節點。
  • 否則會印出 test: <失敗原因>,可能的原因包含:assign_colors 回傳的陣列大小不是 $N$、顏色不是 $0/1/2$、違反顏色平衡限制、find_root 回傳的編號超出 $[1, N]$、或找錯了主節點。

這只是 public/ 資料夾中「範例評測程式(sample grader)」的輸出,純粹用來方便你在本機除錯。正式評測使用的是另一套評測程式,其判定方式與輸出格式和這裡完全無關;你的程式本身也不需要、也不應該印出 test: ... 這類文字(你只要把那兩個函式寫對即可)。

Input Format

你需要實作:

std::vector<int> assign_colors(int n, int r, std::vector<int> u, std::vector<int> v);
  • $n$:樹上的節點數量。
  • $r$:主節點的編號($1 \leq r \leq n$)。
  • $u, v$:長度為 $n-1$ 的陣列,代表樹的邊;第 $i$ 條邊($0$-indexed)連接節點 $u[i]$ 與 $v[i]$。保證這 $n-1$ 條邊確實構成一棵樹,且以 $r$ 為根時,每個節點的子節點數量最多為 $2$。
  • 回傳值:長度為 $n$ 的陣列 colors,其中 colors[i]($0$-indexed)代表編號為 $(i+1)$ 的節點所塗的顏色,必須是 $0, 1,$ 或 $2$。

節點編號一律是 $1$-based:所有節點的編號都是 $1$ 到 $N$ 的整數,因此 $r$、以及 $u[i]$、$v[i]$ 裡存的節點編號都落在 $[1, N]$。請特別留意:陣列 uvcolors 本身是 $0$-indexed(索引從 $0$ 開始),但它們所描述/對應的「節點編號」是 $1$-based(例如 colors[0] 是編號 $1$ 的節點的顏色);Phase 2 的 find_root 要回傳的,也是 $1$-based 的節點編號。

系統會檢查你回傳的顏色陣列是否滿足「每種顏色的節點數量都至少為 $\lfloor n/D \rfloor$」($D$ 依子任務而定:子任務一為 $7$、子任務二為 $3$,見題目敘述的「子任務」一節),若不滿足則直接判定為 Wrong Answer

  • $1 \leq N \leq 10^ 5$
  • $1 \leq R \leq N$
  • 保證輸入的邊構成一棵樹,且以 $R$ 為根時每個節點最多有 $2$ 個子節點。

Output Format

你需要實作:

int find_root(int n, std::vector<int> u, std::vector<int> v, std::vector<int> colors);
  • $n$:樹上的節點數量(與 Phase 1 相同)。
  • $u, v$:長度為 $n-1$ 的陣列,代表節點編號被隨機打亂之後的樹的邊。樹的實體結構(哪些節點相連)與 Phase 1 完全相同,只是每個節點被賦予了一個新的編號。
  • $colors$:長度為 $n$ 的陣列,colors[i]($0$-indexed)代表新編號為 $(i+1)$ 的節點所塗的顏色(也就是 Phase 1 中,同一個節點被指派的顏色)。
  • 回傳值:一個 $1$ 到 $n$ 之間的整數,代表你認為在這個新編號下,哪一個節點是原本的主節點。

只要每一組測試資料都回傳正確的新編號,就會被判定為 Correct;只要有任何一組測試資料回傳錯誤(或不在 $[1, n]$ 範圍內),就會被判定為 Wrong Answer

Sample Input 1

7 1 7
1 2
1 3
2 4
2 5
3 6
3 7

Sample Output 1

test: ok

Sample Input 2

5 3 7
1 2
2 3
3 4
4 5

Sample Output 2

test: ok

Hints

(提醒:這題屬於「互動題」(Communication Problem),並沒有一份固定不變的「標準輸出」;上方範例輸出中的 test: ok 是指用 public/ 資料夾中的本機測試程式,搭配一份正確的實作去執行範例輸入時會印出的內容,並不是要你的程式直接輸出這行文字。)

範測 1 解釋:

$N=7, R=1$,樹的形狀是:節點 $1$ 有兩個子節點 $2,3$;節點 $2$ 有兩個子節點 $4,5$;節點 $3$ 有兩個子節點 $6,7$。

下面用表格示範一次完整的流程(下面的著色方式只是為了說明流程,並不是正確的策略)。

Step 1:Phase 1 收到的樹,以及 assign_colors 的回傳值

假設 assign_colors 單純把節點 $1$(主節點)塗成顏色 $0$,其餘節點都塗成顏色 $1$:

節點(原始編號)1 (root)234567
顏色0111111

Step 2:系統將節點編號完全隨機打亂

假設這次打亂使用的隨機排列如下(實際比賽中每次都是重新隨機產生):

原始編號1234567
打亂後的新編號5371624

樹的連線與每個節點的顏色都跟著編號一起移動,但「原本是哪個編號」這個資訊完全消失。

Step 3:Phase 2 收到打亂後的樹

節點(新編號)1234567
顏色1111011

邊(新編號):$(5,3), (5,7), (3,1), (3,6), (7,2), (7,4)$

find_root 必須只憑上面這張表,判斷出新編號 $\boxed{5}$ 才是原本的主節點——但光憑「只有一個節點顏色是 $0$」這個線索,並沒有辦法保證這一定是唯一符合條件的節點,你需要設計更好的著色策略。

下圖畫出了 Step 1(左)與 Step 3(右)的樹,可以看到連線結構與顏色都完全沒變,只有編號被打亂:

範測 2 解釋:

$N=5, R=3$,樹的形狀是一條鏈 $1-2-3-4-5$,主節點在鏈的中間(節點 $3$)。這說明主節點不一定在樹的「兩端」,你的解法必須能處理主節點在樹中任何位置的情況。

Problem Source

2026 YTP 高中組決賽 p12

Subtasks

No. Testdata Range Constraints Score
1 0~1 範例測試資料 0
2 0~44 塗色需求:每種顏色至少 $\lfloor N/7 \rfloor$ 個節點 8
3 45~86 塗色需求:每種顏色至少 $\lfloor N/3 \rfloor$ 個節點 12

Testdata and Limits

No. Time Limit (ms) Memory Limit (VSS, KiB) Output Limit (KiB) Subtasks
0 4000 262144 65536 1 2
1 4000 262144 65536 1 2
2 4000 262144 65536 2
3 4000 262144 65536 2
4 4000 262144 65536 2
5 4000 262144 65536 2
6 4000 262144 65536 2
7 4000 262144 65536 2
8 4000 262144 65536 2
9 4000 262144 65536 2
10 4000 262144 65536 2
11 4000 262144 65536 2
12 4000 262144 65536 2
13 4000 262144 65536 2
14 4000 262144 65536 2
15 4000 262144 65536 2
16 4000 262144 65536 2
17 4000 262144 65536 2
18 4000 262144 65536 2
19 4000 262144 65536 2
20 4000 262144 65536 2
21 4000 262144 65536 2
22 4000 262144 65536 2
23 4000 262144 65536 2
24 4000 262144 65536 2
25 4000 262144 65536 2
26 4000 262144 65536 2
27 4000 262144 65536 2
28 4000 262144 65536 2
29 4000 262144 65536 2
30 4000 262144 65536 2
31 4000 262144 65536 2
32 4000 262144 65536 2
33 4000 262144 65536 2
34 4000 262144 65536 2
35 4000 262144 65536 2
36 4000 262144 65536 2
37 4000 262144 65536 2
38 4000 262144 65536 2
39 4000 262144 65536 2
40 4000 262144 65536 2
41 4000 262144 65536 2
42 4000 262144 65536 2
43 4000 262144 65536 2
44 4000 262144 65536 2
45 4000 262144 65536 3
46 4000 262144 65536 3
47 4000 262144 65536 3
48 4000 262144 65536 3
49 4000 262144 65536 3
50 4000 262144 65536 3
51 4000 262144 65536 3
52 4000 262144 65536 3
53 4000 262144 65536 3
54 4000 262144 65536 3
55 4000 262144 65536 3
56 4000 262144 65536 3
57 4000 262144 65536 3
58 4000 262144 65536 3
59 4000 262144 65536 3
60 4000 262144 65536 3
61 4000 262144 65536 3
62 4000 262144 65536 3
63 4000 262144 65536 3
64 4000 262144 65536 3
65 4000 262144 65536 3
66 4000 262144 65536 3
67 4000 262144 65536 3
68 4000 262144 65536 3
69 4000 262144 65536 3
70 4000 262144 65536 3
71 4000 262144 65536 3
72 4000 262144 65536 3
73 4000 262144 65536 3
74 4000 262144 65536 3
75 4000 262144 65536 3
76 4000 262144 65536 3
77 4000 262144 65536 3
78 4000 262144 65536 3
79 4000 262144 65536 3
80 4000 262144 65536 3
81 4000 262144 65536 3
82 4000 262144 65536 3
83 4000 262144 65536 3
84 4000 262144 65536 3
85 4000 262144 65536 3
86 4000 262144 65536 3