bzoj 1086 王室聯邦 (dfs,構造)

題意:

思路:

     首先我們dfs,如果一個節點v的兒子u所在的子樹大於等於B,那麼就把這個子樹當作一個省份,對於這種情況,省會是u,v其實都可以。如果一個兒子u所在的子樹小於B,可以先暫存起來,繼續遍歷其他兒子,當暫存的數量大於等於B的時候,將暫存的都歸爲一個省,省會爲v,因爲會暫存的子樹大小爲B-1,所以這樣產生的子樹大小最大爲2B-2,在處理完所有子樹,就把v也加入到暫存的地方返回去,這裏能看出,一個棧很適合處理這個過程。
    這樣一路處理下來,只剩下一個問題,最後,我可能還剩下一個包含根節點的最大B-1個節點的暫存節點。因爲我們之前說子樹最大爲2B-2,所以直接把剩下的暫存節點歸到上一個省份裏面即可(記得改省會)
    我們可以注意到,我們這樣的分塊其實只能保證塊大小,不能保證連通性

錯誤及反思:

    有人說是樹上莫隊前置題目,主要是爲了理解樹上分塊的大致思路。

代碼:

#include<bits/stdc++.h>
using namespace std;
const int N = 1100;
vector<int> son[N];
int n,b;
int ans[N],sh[N],tot=1;
stack<int> s;
void dfs(int now,int fa){
    int si=s.size();
    for(int i=0;i<son[now].size();i++){
        if(son[now][i]!=fa)
        {
            dfs(son[now][i],now);
            //if(now==6) printf("#%d\n",s.size()-si);
            if(s.size()-si>=b){

                while(s.size()!=si){

                    ans[s.top()]=tot;
                    s.pop();
                }
                sh[tot++]=now;
            }
        }
    }
    s.push(now);
}
int main(){
    scanf("%d%d",&n,&b);
    for(int i=0;i<n-1;i++)
    {
        int ta,tb;
        scanf("%d%d",&ta,&tb);
        son[ta].push_back(tb);
        son[tb].push_back(ta);
    }
    dfs(1,1);

    while(!s.empty()){
        ans[s.top()]=tot-1;
        s.pop();
    }
    sh[tot-1]=1;
    tot--;
    printf("%d\n",tot);
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    puts("");
    for(int i=1;i<=tot;i++) printf("%d ",sh[i]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章