• 1086: [SCOI2005]王室联邦


    给定一棵树,要求将这棵树分成一些块,使每块大小在[B,3B]之间

    首先任选一点开始深搜 维护一个栈 每个点退出递归时压栈 自下至上进行合并

    如果某棵子树深搜完之后栈内元素数>=b 就把当前的栈内元素合并为一个块

    但是这种方法存在一个问题 就是如果某棵子树深搜之后不到b 去深搜下一个子树 可能在下一个子树内部的某个位置超过b 这样会导致分成的块不连通

    因此我们在每次进入递归时维护一个栈底,对于当前子树来说这个栈底就是整个栈的底,栈底以下的元素不能修改或弹栈

    这样当一棵子树深搜过后由于子树内未分块节点不超过b,之前搜过的未分块节点数也不超过b,因此每块不超过2b

    那么题目为什么给了3b呢? 深搜结束后可能会剩余一些节点,这些节点的数量不超过b,而且一定与当前分出的最后一块连通

    因此我们将剩余节点分到最后一块中,可以保证最后一块的大小不超过3b

    一遍深搜即可出解。

    //Achen
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<ctime>
    #include<cmath>
    const int N=1005;
    typedef long long LL;
    using namespace std;
    int n,b;
    
    template<typename T> void read(T &x) {
        char ch=getchar(); x=0; T f=1;
        while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
        if(ch=='-') f=-1,ch=getchar();
        for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
    }
    
    int ecnt,fir[N],nxt[N*2],to[N*2],top;
    void add(int u,int v) {
        nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
        nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
    }
    
    int id[N],rt[N],tot,sta[N];
    void dfs(int x,int f) {
        int bot=top;
        for(int i=fir[x];i;i=nxt[i]) if(to[i]!=f) {
            dfs(to[i],x);
            if(top-bot>=b) {
                rt[++tot]=x;
                while(top!=bot) 
                    id[sta[top--]]=tot;
            }
        }
        sta[++top]=x;
    }
    
    void work() {
        dfs(1,0);
        while(top) 
            id[sta[top--]]=tot;
        printf("%d
    ",tot);
        for(int i=1;i<n;i++) printf("%d ",id[i]);
        printf("%d
    ",id[n]);
        for(int i=1;i<tot;i++) printf("%d ",rt[i]);
        printf("%d
    ",rt[tot]);
    }
    
    void init() {
        read(n);
        read(b);
        for(int i=1;i<n;i++) {
            int u,v;
            read(u); read(v);
            add(u,v);
        } 
    }
    
    int main() {
    #ifdef DEBUG
        freopen(".in","r",stdin);
        freopen(".out","w",stdout);
    #endif
        init();
        work();
        return 0;
    }
    王室联邦
  • 相关阅读:
    java代码终于过百行了
    团队建设中人员流失的问题
    将析构函数设置为虚函数,并且析构函数可以为纯虚函数
    J2EE学习笔记——JSP使用Fckeditor
    Android ListView的getview()中position错位 重复调用(position重复调用)
    修正Thinkphp 3.2 分页Page类以支持URL路由
    ThinkPHP中_after_update、_before_update等的用法
    ThinkPHP跨控制器调用方法
    Thinkphp 查询条件 and 和 or同时使用即复合查询
    layer弹出图片的问题
  • 原文地址:https://www.cnblogs.com/Achenchen/p/8021437.html
Copyright © 2020-2023  润新知