• Spanning Tree与度数的一些题


    以下所有图,点数n是1e5,边数是1e6

    CodeForces 1133F1 Spanning Tree with Maximum Degree

    题意:

    找到一个生成树,使得度数最大的点度数最大

    Sol:

    直接找原图中度数最大的点p,把p的所有边都加入生成树,再kruskal即可

    CodeForces 1133F2 Spanning Tree with One Fixed Degree

    题意:

    找到一个生成树,使得1号点度数恰好为K

    Sol:

    法一:

    把一号点删掉,看图被分成了多少个连通块(dfs即可),每个连通块涂成一种颜色

    把一号点和每个连通块至少连一个边。和K比较决定即可。

    或者求割点,如果一号点是割点,也可以求出周围的块(麻烦,注意割点不完全属于任何点双)

     

    法二:

    下面写。

    (ICPC)亚洲区域赛(南京) D.Degree of Spanning Tree

    题意:

    找到一个生成树,使得每个点度数小于n/2

    Sol:

    前面的方法不行了。

    法一:(?)

    求割点,考虑每个割点pi对周围的每个点双至少要连接一条边。

    但是在pi的出边连接的点也是割点pj的时候,无法判断pj“属于”哪个点双。。(反正不会优化。。。。只能n^2)

     

    法二:

    反正来。玩修正主义

    先随便找一个生成树。

    如果有一个点度数>n/2(这样的点最多一个,反证即可),这个点就当作根root。

    考虑其他没有加入的边,如果和root构成环,那么就砍掉root和某个儿子的边,并加入新边。

    注意,加入新边不能使得有新的点度数>n/2,加入的时候判断即可。

     

    这样是对的。

    因为最后正确答案如果存在,那么会有多个。

    在有答案的情况下,(即每个割点连接的点双不多于n/2个)

    随机生成树度数大于n/2的点root,

    如果是原图的割点,那么可以调整

    如果不是原图的割点,那么也可以调整。

     

    实现方法:(比较巧妙)

    (首先可以LCT暴力维护LCA)

    然后其实可以把root的每个儿子子树看成一块,用并查集,开始的时候每个块的点,分别指向对应的root的儿子。

    然后加入边的时候,涉及si,sj两个儿子,

    儿子si和root的边断了,就让si并查集中的father为sj,对应连通块的合并。

    (因为si和root的边不会再连上,所以这样就是对的。)

     

    代码:

    (来源:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=46411249

    #include<bits/stdc++.h>
    using namespace std;
    const int M=5e5+9;
    int n,m,num,root;
    int f[M],u[M],v[M],du[M];
    int head[M],in[M];
    bool vis[M];
    struct P{int to,ne,id;}e[M<<2];
    void dfs(int u,int fa,int top){
        f[u]=top;
        for(int i=head[u];i;i=e[i].ne){
            int v=e[i].to;
            if(v!=fa)dfs(v,u,top);
        }
    }
    int find(int x){
        return f[x]==x?x:f[x]=find(f[x]);
    }
    void work(){
        num=0;root=0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i)f[i]=i,head[i]=0,du[i]=0,in[i]=0;
        for(int i=1;i<=m;++i)vis[i]=0;
        for(int i=1;i<=m;++i){
            scanf("%d%d",&u[i],&v[i]);
            int x=u[i],y=v[i];
            int fx=find(x),fy=find(y);
            if(fx==fy)continue;
            f[fy]=fx;
            e[++num]=P{y,head[x],i};head[x]=num;
            e[++num]=P{x,head[y],i};head[y]=num;
            du[x]++;du[y]++;
            vis[i]=1;
        }
        for(int i=1;i<=n;++i){
            if(find(i)!=find(1)){
                printf("No
    ");
                return;
            }
            if(du[i]>n/2)root=i;
        }
        for(int i=1;i<=n;++i)f[i]=i;
        for(int i=head[root];i;i=e[i].ne){
            in[e[i].to]=e[i].id;
            dfs(e[i].to,root,e[i].to);
        }
        for(int i=1;i<=m;++i){
            int x=u[i],y=v[i];
            int fx=find(x),fy=find(y);
            if(fx==fy)continue;
            if(x==root||y==root)continue;
            if(!in[fy]&&!in[fx])continue;
            du[x]++,du[y]++;
            du[root]--;du[fy]--;
            if(du[x]>n/2||du[y]>n/2){
                du[fy]++;
                du[fx]--;
                if(du[x]>n/2||du[y]>n/2){
                    du[root]++;
                    du[fx]++;
                    du[x]--;du[y]--;
                    continue;
                }
                vis[in[fx]]=0;
                vis[i]=1;
                f[fx]=fy;
                continue;
            }
            vis[in[fy]]=0;
            vis[i]=1;
            f[fy]=fx;
        }
        if(du[root]<=n/2){
            printf("Yes
    ");
            for(int i=1;i<=m;++i){
                int x=u[i],y=v[i];
                if(vis[i])printf("%d %d
    ",x,y);
            }
        }
        else printf("No
    ");
    }
    int main(){
        int T;
        scanf("%d",&T);
        while(T--)work();
        return 0;
    }

    同理,CodeForces 1133F2的做法,也可以是把1号点的所有出边都连上,如果度数大于n/2,那么再调整即可。

    (比ICPC南京 好写多了,不用考虑别的点是否度数会大于n/2)

  • 相关阅读:
    关于一道PHP面试题的解法
    ThinkPHP学习(二)
    ThinkPHP学习(一)
    Apache 创建虚拟主机目录和设置默认访问页面
    awk全集
    初识云计算&openstack
    Python collections
    Python 函数/高阶函数
    Python dic/set/迭代
    python matplotlib 图标绘制
  • 原文地址:https://www.cnblogs.com/Miracevin/p/14285421.html
Copyright © 2020-2023  润新知