• 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
    ");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
    ",ans);
    45     if(ans==0)  return 0;
    46     for(i=1;i<=n;++i){
    47         printf("%d ",bel[i]);
    48     }
    49     printf("
    ");
    50     for(i=1;i<=ans;++i)  printf("%d ",mas[i]);
    51     printf("
    ");
    52     return 0;
    53 }
  • 相关阅读:
    浅谈Dotnet的数据定位和匹配
    聊聊Dotnet的垃圾回收
    Dotnet中Span, Memory和ReadOnlySequence之浅见
    Dotnet的局部函数和委托的对比
    一文说通Dotnet的委托
    开发进阶:Dotnet Core多路径异步终止
    冷饭新炒:理解布隆过滤器算法的实现原理
    冷饭新炒:理解JWT的实现原理和基本使用
    冷饭新炒:理解JDK中UUID的底层实现
    起飞,会了这4个 Intellij IDEA 调试魔法,阅读源码都简单了
  • 原文地址:https://www.cnblogs.com/lazytear/p/9080371.html
Copyright © 2020-2023  润新知