P2325 [SCOI2005]王室聯邦 解題報告
阿新 • • 發佈:2019-01-06
P2325 [SCOI2005]王室聯邦
題目描述
“餘”人國的國王想重新編制他的國家。他想把他的國家劃分成若干個省,每個省都由他們王室聯邦的一個成員來管理。
他的國家有\(n\)個城市,編號為\(1\dots n\)。一些城市之間有道路相連,任意兩個不同的城市之間有且僅有一條直接或間接的道路。為了防止管理太過分散,每個省至少要有\(B\)個城市,為了能有效的管理,每個省最多隻有\(3B\)個城市。
每個省必須有一個省會,這個省會可以位於省內,也可以在該省外。但是該省的任意一個城市到達省會所經過的道路上的城市(除了最後一個城市,即該省省會)都必須屬於該省。
一個城市可以作為多個省的省會。
聰明的你快幫幫這個國王吧!
輸入輸出格式
輸入格式:
第一行包含兩個數\(N\),\(B\)(\(1\le N\le 1000, 1\le B \le N\))。接下來\(N-1\)行,每行描述一條邊,包含兩個數,即這條邊連線的兩個城市的編號。
輸出格式:
如果無法滿足國王的要求,輸出\(0\)。
否則第一行輸出數\(K\),表示你給出的劃分方案中省的個數,編號為\(1\dots K\)。
第二行輸出\(N\)個數,第\(i\)個數表示編號為\(i\)的城市屬於的省的編號。
第三行輸出\(K\)個數,表示這\(K\)個省的省會的城市編號,如果有多種方案,你可以輸出任意一種。
這裡扔一個偷來的圖片,順便問下這是哪個ppt呀
一種樹分塊的方法...我還不知道這東西的實際意義
記錄當前點的棧頂,然後每遍歷完一個兒子,如果棧頂-記錄點的個數大於\(B\),就以這個點為首都扔出來,最後把這個點加進去。
如果最後有剩,放到最後一個點形成的首都裡就行了,可以證明不超過\(3B\)
Code:
#include <cstdio> const int N=1e3+10; int head[N],to[N<<1],Next[N<<1],cnt; int n,B,s[N],rt[N],bel[N],tot,top; void add(int u,int v) { to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt; } void dfs(int now,int fa) { int bot=top; for(int v,i=head[now];i;i=Next[i]) if((v=to[i])!=fa) { dfs(v,now); if(top-bot>=B) { rt[++tot]=now; while(top!=bot) bel[s[top--]]=tot; } } s[++top]=now; } int main() { scanf("%d%d",&n,&B); for(int u,v,i=1;i<n;i++) scanf("%d%d",&u,&v),add(u,v),add(v,u); dfs(1,0); while(top) bel[s[top--]]=tot; printf("%d\n",tot); for(int i=1;i<=n;i++) printf("%d ",bel[i]); puts(""); for(int i=1;i<=tot;i++) printf("%d ",rt[i]); return 0; }
2019.1.6