• 暑假集训每日一题 0725 (强连通分量)


    Description

    N个学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输。
    问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。
    问题2:至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

    Input

    输入有多组样例,大约1000组。
    每组样例第一行包含两个整数N,M(2<=N<=100),N代表学校的个数,M代表边的个数(M<N*N)
    接下来M行,每行包含连个整数u,v,代表u可以向v单向发送数据。

    Output

    每组样例对应两行,分别是问题一和问题二的解。

    Sample Input

    7 8
    1 2
    2 3
    3 1
    1 4
    4 5
    5 6
    6 4
    7 6

    Sample Output

    2
    2
     
     
    分析,属于同一强连通分量的学校可以共享软件,所以可以将属于同一强连通分量的学校看成一个学校,这就是缩点,缩点后的有向图是一个有向无环图,此时需要的软件的个数就是入度为0的结点的数目。而要将所有点都连到一个强连通分量内,简单的想法就是使所有点的入度和出度都不为0.因此需添加的边数就是入度和出度中的较大者(相当于从叶子到树根连边)。
    需要注意的是,有一种特殊情况,那就是所有点本来就属于同一个强连通分量内。
     
    2遍dfs
    #include <stdio.h>
    #include <string.h>
    #define MAX(a,b) ((a)>(b)?(a):(b))
    #define N 101
    int g[N][N];
    int n,m;
    int ans1,ans2;
    int cnt;
    int vis[N],dfn[N],id[N];
    int din[N],dout[N];
    void dfs(int u)
    {
        int v;
        vis[u]=1;
        for(v=1;v<=n;v++)
        {
            if(g[u][v] && !vis[v]) dfs(v);
        }
        dfn[cnt++]=u;
    }
    void rdfs(int u)
    {
        int v;
        vis[u]=1;
        id[u]=cnt;
        for(v=1;v<=n;v++)
        {
            if(g[v][u] && !vis[v])  rdfs(v);
        }
    }
    void solve()
    {
        int i,j,t;
        memset(vis,0,sizeof(vis));
        cnt=0;
        for(i=1;i<=n;i++)
        {
            if(!vis[i]) dfs(i);
        }
        memset(vis,0,sizeof(vis));
        cnt=0;
        for(t=n-1;t>=0;t--)
        {
            i=dfn[t];
            if(!vis[i]) rdfs(i),cnt++;
        }
        memset(din,0,sizeof(din));
        memset(dout,0,sizeof(dout));
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(id[i]!=id[j]&&g[i][j]) dout[id[i]]++,din[id[j]]++;
            }
        }
        ans1=ans2=0;
        for(i=0;i<cnt;i++)
        {
            if(!din[i])   ans1++;
            if(!dout[i])    ans2++;
        }
        if(cnt==1)  printf("1\n0\n");
        else    printf("%d\n%d\n",ans1,MAX(ans1,ans2));
    }
    int main()
    {
        int u,v;
        while(~scanf("%d%d",&n,&m))
        {
            memset(g,0,sizeof(g));
            while(m--)
            {
                scanf("%d%d",&u,&v);
                g[u][v]=1;
            }
            solve();
        }
        return 0;
    }
    tarjan
    #include <stdio.h>
    #include <string.h>
    #define MIN(a,b) ((a)<(b)?(a):(b))
    #define MAX(a,b) ((a)>(b)?(a):(b))
    #define N 101
    int g[N][N];
    int n,m;
    int cnt,num;
    int dfn[N],low[N];
    int stk[N],ins[N],top;
    int id[N];
    int din[N],dout[N];
    void dfs(int u)
    {
        int v,tmp;
        dfn[u]=low[u]=cnt++;
        stk[top++]=u;
        ins[u]=1;
        for(v=1;v<=n;v++)   if(g[u][v])
        {
            if(dfn[v]==-1) dfs(v),low[u]=MIN(low[u],low[v]);
            else if(ins[v]) low[u]=MIN(low[u],dfn[v]);
        }
        if(dfn[u]==low[u])
        {
            do
            {
                tmp=stk[--top];
                id[tmp]=num;
                ins[tmp]=0;
            }while(tmp!=u);
            num++;
        }
    }
    void solve()
    {
        int i,j,ans1,ans2;
        cnt=num=top=0;
        memset(ins,0,sizeof(ins));
        memset(dfn,-1,sizeof(dfn));
        for(i=1;i<=n;i++)
        {
            if(dfn[i]==-1)  dfs(i);
        }
        memset(din,0,sizeof(din));
        memset(dout,0,sizeof(dout));
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(id[i]!=id[j] && g[i][j])  dout[id[i]]++,din[id[j]]++;
            }
        }
        ans1=ans2=0;
        for(i=0;i<num;i++)
        {
            if(!din[i]) ans1++;
            if(!dout[i])    ans2++;
        }
        if(num==1)   printf("1\n0\n");
        else    printf("%d\n%d\n",ans1,MAX(ans1,ans2));
    }
    int main()
    {
        int u,v;
        while(~scanf("%d%d",&n,&m))
        {
            memset(g,0,sizeof(g));
            while(m--)
            {
                scanf("%d%d",&u,&v);
                g[u][v]=1;
            }
            solve();
        }
        return 0;
    }
  • 相关阅读:
    【python实现卷积神经网络】池化层实现
    【python实现卷积神经网络】批量归一化层实现
    在CentOS Linux系统上,添加新的端口,启用ssh服务
    linux各文件夹的作用
    断网环境下利用pip安装Python离线安装包
    Python数据分析入门之pandas基础总结
    Git入门私房菜
    python处理json
    Json概述以及python对json的相关操作
    将Sublime Text 添加到鼠标右键菜单的教程方法
  • 原文地址:https://www.cnblogs.com/algorithms/p/2610408.html
Copyright © 2020-2023  润新知