• Codeforces Round #377 (Div. 2) F


    前言:关于如何求双连通分量,我们可以在tarjan搜索时标记下所有桥的位置(双连通分量(可以认为是没有桥的无向图图)即可通过删去所有桥得到),那么怎么找桥呢,对于每一条搜索到的边u->x,如果low【u】>dfn【x】则说明u不能通过子图到达比x更早的节点,那么就说明该边是桥

    题意:把一个无向图变成有向图,对于这个有向图来说,每个点的价值是它所有能到达的点的数量,要求使得所有点中最小的价值最大

    题解:现学的边-双联通分量,先求一遍边-双联通分量,然后在每个双连通分量里dfs一边把双向边变成单向边,最后从点数最大的那个双连通分量开始dfs,删去反向边,易证最大的点数就是答案,然后直接输出单向边即可

    #include<bits/stdc++.h>
    #include<ext/rope>
    #define fi first
    #define se second
    #define mp make_pair
    #define pb push_back
    #define pii pair<int,int>
    #define C 0.5772156649
    #define pi acos(-1.0)
    #define ll long long
    #define mod 1000000007
    #define ls l,m,rt<<1
    #define rs m+1,r,rt<<1|1
    
    using namespace std;
    using namespace __gnu_cxx;
    
    const double g=10.0,eps=1e-7;
    const int N=400000+10,maxn=100000+10,inf=0x3f3f3f;
    
    map<int,int>ma[N];
    map<int,int>ans[N];
    vector<int>v[N];
    int dfn[N],low[N];
    int a[N],b[N];
    int index,sz;
    void tarjan(int u,int f)
    {
        dfn[u]=low[u]=++index;
        for(int i=0;i<v[u].size();i++)
        {
            int x=v[u][i];
            if(x==f)continue;
            if(!dfn[x])
            {
                tarjan(x,u);
                low[u]=min(low[u],low[x]);
                if(low[x]>dfn[u])ma[u][x]=ma[x][u]=1;
            }
            else low[u]=min(low[u],dfn[x]);
        }
    }
    void init(int n)
    {
        memset(dfn,0,sizeof dfn);
        memset(low,0,sizeof low);
        index=0;
        for(int i=1;i<=n;i++)
        {
            ma[i].clear();
            v[i].clear();
            ans[i].clear();
        }
    }
    void dfs(int u,int f)
    {
        dfn[u]=1;
        sz++;
        for(int i=0;i<v[u].size();i++)
        {
            int x=v[u][i];
            if(!ma[x][u]&&x!=f)
            {
           //     cout<<u<<" "<<x<<endl;
                if(ans[x][u]&&ans[u][x])ans[x][u]=0;
                if(!dfn[x])dfs(x,u);
            }
        }
    }
    void dfs2(int u,int f)
    {
        dfn[u]=1;
        for(int i=0;i<v[u].size();i++)
        {
            int x=v[u][i];
            if(!dfn[x])
            {
                if(ans[x][u]&&ans[u][x])ans[u][x]=0;
                dfs2(x,u);
            }
        }
    }
    int main()
    {
        int n,m;
        cin>>n>>m;
        init(n);
        for(int i=0;i<m;i++)
        {
            cin>>a[i]>>b[i];
            ans[a[i]][b[i]]=ans[b[i]][a[i]]=1;
            v[a[i]].pb(b[i]);
            v[b[i]].pb(a[i]);
        }
        tarjan(1,-1);
        memset(dfn,0,sizeof dfn);
        int maxx=0,id;
        for(int i=1;i<=n;i++)
        {
            if(!dfn[i])
            {
                sz=0;
                dfs(i,-1);
                if(maxx<sz)
                {
                    maxx=sz;
                    id=i;
                }
            }
        }
        memset(dfn,0,sizeof dfn);
        dfs2(id,-1);
        cout<<maxx<<endl;
        for(int i=0;i<m;i++)
        {
            if(ans[a[i]][b[i]])cout<<a[i]<<" "<<b[i]<<endl;
            else cout<<b[i]<<" "<<a[i]<<endl;
        }
        return 0;
    }
    /************
    7 8
    1 2
    2 3
    1 3
    3 4
    4 5
    5 6
    6 7
    7 4
    ************/
    View Code
  • 相关阅读:
    【WPF】WPF的二维路径标记语法绘图PathGeometry
    【转】【WPF】WPF无边框窗体
    【转】【数学】矩阵求逆的几何意义
    【转】【数学】矩阵的旋转
    【转】【OPenGL】理解OpenGL拾取模式(OpenGL Picking)
    WPF DataGrid 表头单元格居中DataGridCheckBoxColumn居中单击选中
    Revit 调用自己的窗体,以及导出图纸图片
    OpenXml 学习记录 标签目录 插入文本 表格 图片
    【转】【OpenXML】OpenXML操作word
    【转】【OpenXml】OpenXml操作Word的一些操作总结
  • 原文地址:https://www.cnblogs.com/acjiumeng/p/7744852.html
Copyright © 2020-2023  润新知