zoukankan      html  css  js  c++  java
  • 暑假集训每日一题 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;
    }
  • 相关阅读:
    mysql BETWEEN操作符 语法
    mysql IN操作符 语法
    mysql LIKE通配符 语法
    mysql TOP语句 语法
    mysql DELETE语句 语法
    mysql Update语句 语法
    mysql INSERT语句 语法
    mysql ORDER BY语句 语法
    mysql OR运算符 语法
    mysql AND运算符 语法
  • 原文地址:https://www.cnblogs.com/algorithms/p/2610408.html
Copyright © 2011-2022 走看看