• [SCOI2005]王室联邦


    1086: [SCOI2005]王室联邦

    http://www.lydsy.com/JudgeOnline/problem.php?id=1086

    Time Limit: 10 Sec  Memory Limit: 162 MBSec  Special Judge

    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
    dfs+分块
    讲课的时候老师专门用这道题命名了一种分块方式——王室联邦分块
    个人理解:
    一边dfs,一边分块
    对与以x为根的子树来说,如果它的大小满足了要求,就把子树除去根节点(即除去x)分为一块
    为什么要除去x?后面说
    不满足要求,它的大小累计至它的父节点(可以理解为分入等待区,等待被划分为一块),与兄弟节点的子树合并,直至满足大小,划分为一块
    若一直不满足大小,就一直累计上去,直至根节点
    最后累计至根节点的怎么办?
    那本题来说,这题[B,3B]给的非常巧
    首先一直向下递归至最底层、自底层向上合并,
    以x为根子树大小<B的累积至父节点,与兄弟节点子树合并为一个子树
    >=B,除去x划分出一块
    因为是自底层向上,所以保证不会有子树大小>=2B
    因为在>=2B之前,一定会先>=B,划分为一块
    若想合并为一块,则子树满足两个条件:
    1、两子树大小均<B,否则早就划分为一块
    2、两子树大小相加>=B
    同时,我们可以推出,合并划分出的一块大小<=2B
    所以,对于最后累积至根节点的值,合并到离根节点最近的一块里就行
    现在说说为什么要除去子树的根节点?
    假设x有3个子树1、2、3
    1、2合并可划分为一块,3不能自己划分为一块
    那么应该1、2合并,归为一块,3向上累积至x
    如果划分1、2为一块时不除去x,也就是1、2、x为一块
    那么3就无法通过父节点x与上面联通
    1、用栈辅助输出城市为哪个省
    #include<cstdio>
    #define N 1001
    using namespace std;
    int n,b,tot,stack[N],top,bl[N],now;
    int to[N*2],next[N*2],front[N],sum[N],id[N],cap[N];
    bool v[N];
    void add(int u,int v)
    {
        to[++tot]=v;next[tot]=front[u];front[u]=tot;
        to[++tot]=u;next[tot]=front[v];front[v]=tot;
    }
    void dfs(int x,int fa)
    {
        stack[++top]=x;
        for(int i=front[x];i;i=next[i])
        {
            if(to[i]==fa) continue;
            dfs(to[i],x);
            if(sum[x]+sum[to[i]]>=b) 
            {
                cap[++now]=x;
                sum[x]=0;
                while(stack[top]!=x) bl[stack[top--]]=now; 
            }
            else sum[x]+=sum[to[i]];    
        }
        sum[x]++;
    }
    int main()
    {
        scanf("%d%d",&n,&b);
        if(n<b) 
        {
            printf("0");
            return 0;
        }
        int x,y;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        dfs(1,0);
        while(top) bl[stack[top--]]=now;
        printf("%d
    ",now);
        for(int i=1;i<=n;i++) printf("%d ",bl[i]);
        printf("
    ");
        for(int i=1;i<=now;i++) printf("%d ",cap[i]);
    }
    View Code

    2、递归标记城市为哪个省

    #include<cstdio>
    #define N 1001
    using namespace std;
    int n,b,tot;
    int to[N*2],next[N*2],front[N],sum[N],id[N],cap[N],now;
    bool v[N];
    void add(int u,int v)
    {
        to[++tot]=v;next[tot]=front[u];front[u]=tot;
        to[++tot]=u;next[tot]=front[v];front[v]=tot;
    }
    void mark(int x,int fa)
    {
         
        for(int i=front[x];i;i=next[i])
         if(to[i]!=fa&&!id[to[i]]&&v[to[i]])
            {
                id[to[i]]=now;mark(to[i],x);
            }
    }
    void dfs(int x,int fa)
    {
        v[x]=true;
        for(int i=front[x];i;i=next[i])
        {
            if(to[i]==fa) continue;
            dfs(to[i],x);
            sum[x]+=sum[to[i]];
            if(sum[x]>=b) 
            {
                now++;
                mark(x,fa);
                cap[now]=x;
                sum[x]=0;
            }   
        }
        sum[x]++;
    }
    int main()
    {
        scanf("%d%d",&n,&b);
        int x,y;
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y);
        }
        dfs(1,0);
        for(int i=1;i<=n;i++) 
         if(!id[i]) id[i]=now;
        printf("%d
    ",now);
        for(int i=1;i<=n;i++) printf("%d ",id[i]);
        printf("
    ");
        for(int i=1;i<=now;i++) printf("%d ",cap[i]);
    }
    
    View Code
     
     
  • 相关阅读:
    python核心编程(多线程编程)
    Python核心编程(网络编程)
    将非drf接口配置到swagger
    jmeter设置全局变量--通过正则表达式进行提取
    jmeter实现用户登录高并发
    Django跨关联关系查询
    python树状结构取值和加值
    chrome浏览器代理插件SwitchyOmega使用
    burp suite历程-安装burp suite
    django中对模型字段名的限制
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6556222.html
Copyright © 2020-2023  润新知