【塊狀樹】BZOJ 1086: [SCOI2005]王室聯邦

1086: [SCOI2005]王室聯邦

Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge
Submit: 826  Solved: 471
[Submit][Status][Discuss]

Description

“餘”人國的國王想重新編制他的國家。他想把他的國家劃分成若干個省,每個省都由他們王室聯邦的一個成員來管理。他的國家有n個城市,編號爲1..n。一些城市之間有道路相連,任意兩個不同的城市之間有且僅有一條直接或間接的道路。爲了防止管理太過分散,每個省至少要有B個城市,爲了能有效的管理,每個省最多隻有3B個城市。每個省必須有一個省會,這個省會可以位於省內,也可以在該省外。但是該省的任意一個城市到達省會所經過的道路上的城市(除了最後一個城市,即該省省會)都必須屬於該省。一個城市可以作爲多個省的省會。聰明的你快幫幫這個國王吧!

Input

第一行包含兩個數N,B(1<=N<=1000, 1 <= B <= N)。接下來N-1行,每行描述一條邊,包含兩個數,即這條邊連接的兩個城市的編號。

Output

如果無法滿足國王的要求,輸出0。否則輸出數K,表示你給出的劃分方案中省的個數,編號爲1..K。第二行輸出N個數,第I個數表示編號爲I的城市屬於的省的編號,第三行輸出K個數,表示這K個省的省會的城市編號,如果有多種方案,你可以輸出任意一種。

Sample Input

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

Sample Output

3
2 1 1 3 3 3 3 2
2 1 8

  很容易想到每次搜子樹
  不過好像每次搜索出的殘餘又要和回溯上去的子樹湊
  會非常麻煩
  然後只能看題解
  copy一下
  因此我們在每次進入遞歸時維護一個棧底,對於當前子樹來說這個棧底就是整個棧的底,棧底以下的元素不能修改或彈棧
  這樣當一棵子樹深搜過後由於子樹內未分塊節點不超過b,之前搜過的未分塊節點數也不超過b,因此每塊不超過2b
  那麼題目爲什麼給了3b呢?
  深搜結束後可能會剩餘一些節點,這些節點的數量不超過b,而且一定與當前分出的最後一塊連通
  因此我們將剩餘節點分到最後一塊中,可以保證最後一塊的大小不超過3b
  
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<algorithm>
 5 
 6 #define maxn 1001
 7 
 8 using namespace std;
 9 
10 inline int in()
11 {
12     int x=0;char ch=getchar();
13     while(ch<'0'||ch>'9')ch=getchar();
14     while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
15     return x;
16 }
17 
18 int n,l,last[maxn],tot=0,sta[maxn],top=0,father[maxn],root[maxn],cnt=0;
19 
20 struct ed{
21     int to,last;
22 }edge[maxn*2];
23 
24 void add(int u,int v)
25 {
26     edge[++tot].to=v,edge[tot].last=last[u],last[u]=tot;
27     edge[++tot].to=u,edge[tot].last=last[v],last[v]=tot;
28 }
29 
30 void dfs(int poi,int Last)
31 {
32     int lim=top;
33     for(int i=last[poi];i;i=edge[i].last)if(edge[i].to!=Last){
34         dfs(edge[i].to,poi);
35         if(top-lim>=l)
36         {
37             root[++cnt]=poi;
38             while(top!=lim)father[sta[top--]]=cnt;
39         }
40     }
41     sta[++top]=poi;
42 }
43 
44 int main()
45 {
46     int u,v;
47     n=in();l=in();
48     for(int i=1;i<n;i++)
49         u=in(),v=in(),add(u,v);
50     dfs(1,0);
51     while(top)father[sta[top--]]=cnt;
52     printf("%d\n",cnt);
53     for(int i=1;i<=n;i++)printf("%d ",father[i]);
54     printf("\n");
55     for(int i=1;i<=cnt;i++)printf("%d ",root[i]);
56     return 0;
57 }
View Code

 

  
發佈了84 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章