• BZOJ 5201 Connections


    原文链接:https://blog.csdn.net/qq_34283998/java/article/details/82983653

    [NEERC2017]Connections

    给定一个n个点,m条边的强连通有向图。请保留其中恰好2n条边,使得它还是强连通的。
    Input
    第一行包含一个正整数T,表示测试数据的组数。
    每组数据第一行包含两个正整数n,m(n>=4,m>2n),表示点数和边数。
    接下来m行,每行两个正整数x,y(1<=x,y<=n,x!=y),表示一条x到y的单向边。
    数据保证图强连通,且不存在重边,sum(n),sum(m)<=100000。
    Output
    对于每组数据,输出m-2n行
    每行描述一条要被删除的边,和输入格式一样,有多解输出任意一组。
    Sample Input
    1

    4 9

    1 2

    1 3

    2 3

    2 4

    3 2

    3 4

    4 1

    4 2

    4 3
    Sample Output
    1 3

    对于每一个节点,我们保留一条树边,以及最多一条返祖边.注意这条返祖边要指向尽可能高的位置.这样下来保留的边数一定小于等于2∗n 2*n2∗n,并且满足图依旧是强连通的.至于为什么,贪心的想一想.既然之前满足强连通,我们保留走到dfn最小的返祖边后也一定是强连通的.最后随意乱加边直到2∗n 2*n2∗n即可.
    只需进行一次Tarjan,保留树边,并在过程中维护出当前点通过返祖边走向的dfn最小的点,然后保留这条返祖边.

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAXN=100005;
    int n,m,ncnt,tot;
    int dfn[MAXN],edge[MAXN];
    bool vis[MAXN];
    int head[MAXN],ecnt;
    struct node{
        int v,nxt;
    }E[MAXN*2];
    
    void addedge(int u,int v)
    
    {
        E[++ecnt]=(node){v,head[u]};
        head[u]=ecnt;
    }
    
    void Tarjan(int u)
    {
        dfn[u]=++ncnt;
        for(int i=head[u];i;i=E[i].nxt)
    	{
            int v=E[i].v;
            if(!dfn[v])
    		{
                vis[i]=1,tot++;//选择一条树边 
                Tarjan(v);
            }
            else 
    		if(dfn[v]<dfn[E[edge[u]].v]) //选择一条返祖边,并且其DFN的值尽可能的小 
    		    edge[u]=i;
        }
        if(edge[u]) //将选择的返祖边打上标记 
    	   tot++,vis[edge[u]]=1;
    }
    
    int main(){
        int T;
        scanf("%d",&T);
        while(T--){
            ecnt=ncnt=tot=0;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++) edge[i]=head[i]=dfn[i]=0;
            for(int i=1;i<=m;i++) vis[i]=0;
            for(int i=1;i<=m;i++)
    		{
                int u,v;
                scanf("%d%d",&u,&v);
                addedge(u,v);
            }
            dfn[0]=0x3f3f3f3f;
            Tarjan(1);
            for(int i=1;i<=m&&tot<2*n;i++)
                if(!vis[i]) 
    			    vis[i]=1,tot++;
            for(int u=1;u<=n;u++)
                for(int i=head[u];i;i=E[i].nxt)
                    if(!vis[i]) printf("%d %d
    ",u,E[i].v);
        }
    }
    

      

  • 相关阅读:
    五分钟小知识:为什么要分稳定排序和非稳定排序?
    spring boot——配置文件——Spring Boot Profile(多环境配置)——多 Profile 文件方式——properties 配置
    Osquery检测入侵痕迹——这玩意适合在agent端侧使用啊
    2021 fireeye apt攻击报告
    PostgreSQL 使用citd删除重复行 规格严格
    Go Web编程深入学习解析HTTP请求
    网速成为了工作的瓶颈之一
    进销存成本的影响因素
    系统升级时,数据库脚本执行注意事项,血的教训
    进销存系统的成本核算方法一览
  • 原文地址:https://www.cnblogs.com/cutemush/p/12688568.html
Copyright © 2020-2023  润新知