暑假集训每日一题 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;
}

 

posted @ 2012-07-26 17:19  BeatLJ  阅读(186)  评论(0编辑  收藏  举报