bzoj1086[SCOI2005]王室联邦

传送门

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

题解

如果有一颗子树,我们把它上面的点划分到一个省以内,那么省会一定是这个子树上的点或者子树的根节点的父亲节点。那么我们可以判断出除非n<b,否则题目一定有解。因此我们考虑对其分块,用一个栈维护。从根节点向下dfs,每次向栈中压入当前访问的值。每当子树大小大于b时,就将其记录成一块,根为省会。最后一定剩下不到b个节点,我们分的每一块的大小一定大于等于b且小于2b。所以我们把剩下的节点全部丢到最后一块中,就可以求出一个解了。

代码

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 int ans=0,n,cnt=1,t=0,b;
 8 struct node{
 9     int to,nxt;
10 }e[10010];
11 int head[1010],bel[1010],mas[1010],sta[2010];
12 void add(int u,int v){
13     e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
14     e[++cnt].to=u;e[cnt].nxt=head[v];head[v]=cnt;
15 }
16 void dfs(int x,int fa){
17     int now=t;
18     int i;
19     for(i=head[x];i;i=e[i].nxt){
20         if(e[i].to!=fa){
21             dfs(e[i].to,x);
22             if(t-now>=b){
23                 mas[++ans]=x;
24                 while(t!=now){
25                     bel[sta[t--]]=ans;
26                 }
27             }
28         }
29     }
30     sta[++t]=x;
31 }
32 int main(){
33     scanf("%d%d",&n,&b);
34     if(n<b){
35         printf("0\n");return 0;
36     }
37     int i,j,x,y;
38     for(i=1;i<n;++i){
39         scanf("%d%d",&x,&y);
40         add(x,y);
41     }
42     dfs(1,0);
43     while(t)  bel[sta[t--]]=ans;
44     printf("%d\n",ans);
45     if(ans==0)  return 0;
46     for(i=1;i<=n;++i){
47         printf("%d ",bel[i]);
48     }
49     printf("\n");
50     for(i=1;i<=ans;++i)  printf("%d ",mas[i]);
51     printf("\n");
52     return 0;
53 }

 

posted @ 2018-05-23 23:31  lazytear  阅读(...)  评论(... 编辑 收藏