1. 程式人生 > >P2325 [SCOI2005]王室聯邦 解題報告

P2325 [SCOI2005]王室聯邦 解題報告

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