zoukankan      html  css  js  c++  java
  • ICPC World Finals 2019 E

    题意:

    给出一张无向图

    如果有一条边(u,v)满足从u走到v除了立刻从这条边折返无法走回u,那这条边就是死胡同

    现在要对所有的死胡同进行标记,即如果从点u走边e是一个死胡同,就在边e靠近u的入口处标记

    这样有的标记是冗余的,要去点

    比如如果从a会进入一个标记的死胡同e1,从b会进入一个标记的死胡同e2,从a走e1可以到b然后进入e2,那么在e2的标记就是冗余的

    问最少有多少个标记,能让所有的死胡同被标记到

    升序输出方案

    巨麻烦做法

    一条链,标记两端

    一棵树,标记所有度为1的点

    一个环,不用标记

    两个环及连接两个环之间的边,不用标记

    所以

    tarjan缩点,重新建图之后

    在新图上从一个缩环的点为根开始dfs

    如果一条边连出去的子树没有环,那么这条边需要在靠近当前根节点的位置标记

    如果一条边连出去的子树有环,继续dfs

    最后处理所有的树

    注意一条边两个点,需要标记两次

    #include<cstdio>
    #include<algorithm>
    
    using namespace std; 
    
    #define N 600001
    
    int n,m;
    int front[N],to[N<<1],nxt[N<<1],tot=1;
    int ui[N],vi[N];
    
    int dfn[N],low[N]; 
    int st[N],top;
    int col[N],col_cnt,siz[N];
    
    int FRONT[N],TO[N<<1],NXT[N<<1],TOT;
    int aa[N<<1],bb[N<<1];
    int d[N]; 
    bool have[N<<1];
    
    bool vis[N];
    
    struct edge
    {
        int a,b;
    }e[N];
    int ans;
    
    void add(int u,int v)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    }
    
    void ADD(int u,int v,int uu,int vv)
    {
        TO[++TOT]=v; NXT[TOT]=FRONT[u]; FRONT[u]=TOT;
        d[u]++;
        aa[TOT]=uu; bb[TOT]=vv;
    }
    
    void tarjan(int x,int y)
    {
    
        dfn[x]=low[x]=++tot;
        st[++top]=x;
        int t;
        for(int i=front[x];i;i=nxt[i])
        {
            if(i==(y^1)) continue;
            t=to[i];
            if(!dfn[t])
            {
                tarjan(t,i);
                low[x]=min(low[x],low[t]);
            }
            else low[x]=min(low[x],dfn[t]);
        }
        if(dfn[x]==low[x])
        {
            col_cnt++;
            while(st[top]!=x) 
            {
                col[st[top--]]=col_cnt;
                siz[col_cnt]++;
            }
            col[st[top--]]=col_cnt;
            siz[col_cnt]++;
        }
    }
    
    void rebuild()
    {
        tot=0;
        for(int i=1;i<=n;++i)
            if(!dfn[i]) tarjan(i,0);
        for(int i=1;i<=m;++i)
        {
            if(col[ui[i]]==col[vi[i]]) continue;
            ADD(col[ui[i]],col[vi[i]],ui[i],vi[i]);
            ADD(col[vi[i]],col[ui[i]],vi[i],ui[i]);
        }
    }
    
    bool cmp(edge p,edge q)
    {
        if(p.a!=q.a) return p.a<q.a;
        return p.b<q.b; 
    }
    
    void solve_tree()
    {
        for(int i=1;i<=m;++i)
        {
            if(vis[col[ui[i]]] || vis[col[vi[i]]]) continue;
            if(d[col[ui[i]]]==1 && d[col[vi[i]]]==1)
            {
                e[++ans].a=ui[i];
                e[ans].b=vi[i];
                e[++ans].a=vi[i];
                e[ans].b=ui[i];
            }
            else if(d[col[ui[i]]]==1)
            {
                e[++ans].a=ui[i];
                e[ans].b=vi[i]; 
            }
            else if(d[col[vi[i]]]==1)
            {
                e[++ans].a=vi[i];
                e[ans].b=ui[i];
            }
        }
    }
    
    bool dfs(int x,int fa)
    {
        vis[x]=true;
        int t;
        bool th=false;
        for(int i=FRONT[x];i;i=NXT[i])
        {
            t=TO[i];
            if(t==fa) continue;
            if(dfs(t,x))
            {
                have[i]=true;
                th=true;
            }
        } 
        return th | (siz[x]!=1);
    }
    
    void dfs2(int x,int y)
    {
        int t;
        bool th=false;
        for(int i=FRONT[x];i;i=NXT[i])
        {
            t=TO[i];
            if(t==y) continue;
            if(!have[i])
            {
                e[++ans].a=aa[i];
                e[ans].b=bb[i];
            }
            else dfs2(t,x);
        }
    }
    
    void solve_circle(int rt)
    {
        dfs(rt,0);
        dfs2(rt,0);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;++i)
        {
            scanf("%d%d",&ui[i],&vi[i]);
            add(ui[i],vi[i]);
            add(vi[i],ui[i]);
        }
        rebuild();
        for(int i=1;i<=col_cnt;++i)
        {
            if(vis[i]) continue;
            if(siz[i]!=1) solve_circle(i);
        }
        solve_tree();
        printf("%d
    ",ans);
        sort(e+1,e+ans+1,cmp);
        for(int i=1;i<=ans;++i) printf("%d %d
    ",e[i].a,e[i].b); 
    }
  • 相关阅读:
    Java学习第一课:搭建Eclipse+MyEclipse+Tomcat
    XFire 与 JAXWS的区别 GlassFish是Java EE 5的开源实现其中包括JAXWS
    在MyEclipse6.5上开发JAXWS web服务
    adobe acrobat professional8 .0 激活方法实施过程 记录
    MySQL MYSQL_ROW 返回的字段若是 float 如何在 C++程序中 把 字段值赋给 一个 float变量
    Arrays.sort 不区分大小写 排序
    Arrays.sort 不区分字母大小写 排序
    Applet与Servlet通讯的四种方法及其比较
    Arrays.sort 不区分大小写字母 Comparable
    利用 Arrays.sort 字符串 进行排序 完全按字符 排序 忽略字符大小写
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/14090301.html
Copyright © 2011-2022 走看看