kuangbin专题-连通图A - Network of Schools

这道题的意思是就是

问题

1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。

2:至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

 其实问题1就是问,这个图的支配集有多少???解决这个问题非常简单,把图缩点后,找到有多少个入度为0的点,就是支配集。一个支配内,所有点可能不是强连通的,但是都可以通过这个点到达。

  而问题二其实更加简单,我们只需要把入读为0的点和出度为0的点的数目取一个最大值即可,至于问什么,很简单,我们可以把出度为0的点连接到入度为0的点上面去,这样就保证图的强连通性质。其实这就是求一个图的补图。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N = 100010,M=1000010;
int ver[M],Next[M],head[N],dfn[N],low[N];
int sta[N],ins[N],c[N],in_deg[N],out_deg[N];
int n,m,tot,num,top,cnt;
void add(int x,int y)
{
    ver[++tot]=y,Next[tot]=head[x],head[x]=tot;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++num;//序列号+1
    sta[++top]=x,ins[x]=1;//入栈,并标记在栈内
    for (int i=head[x]; i; i=Next[i])  //开始访问
        if(!dfn[ver[i]]) //如果没有被处理过
        {
            tarjan(ver[i]);//DFS
            low[x]=min(low[x],low[ver[i]]);
//递归出来,比较谁是谁的儿子/父亲,就是树的对应关系,涉及到强连通分量子树最小根的事情
        }
        else if (ins[ver[i]])
            low[x]=min(low[x],dfn[ver[i]]);
//比较谁是谁的儿子/父亲。就是链接对应关系
        if (dfn[x] == low[x])//发现是整个强连通分量的子树里面的最小根。
        {
            cnt++;
            int y;
            do
            {
                y=sta[top--],ins[y]=0;
                c[y]=cnt;
                //scc[cnt].push_back(y);
            }
            while(x!=y);
        }
}
void solve(int n)
{
    for (int i=1; i<=n; i++)
    {
        if (!dfn[i])
        {
            tarjan(i);
        }
    }
    if (cnt==1)
    {
        printf("1\n0\n");
        return;
    }
    for (int u=1; u<=n; ++u)
    {
        for (int j=head[u]; j; j=Next[j])
        {
            int v=ver[j];
            if (c[u]==c[v])
            {
                continue;
            }
            out_deg[c[u]]++;
            in_deg[c[v]]++;
        }
    }
    int a,b;
    a=0;
    b=0;
    for (int i=1; i<=cnt; i++)
    {
        if (in_deg[i]==0)
        {
            a++;
        }
        else if (out_deg[i]==0)
        {
            b++;
        }
    }
    printf("%d\n",a);
    printf("%d\n",max(a,b));

}
void init()
{
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(head,0,sizeof(head));
    memset(in_deg,0,sizeof(in_deg));
    memset(out_deg,0,sizeof(out_deg));
    memset(ins,0,sizeof(ins));
    top=0;
    tot=0;
    cnt=0;
    num=0;
}
int main()
{
    int  tmp;
    while(~scanf("%d",&n))
    {
        init();
        for (int i=1; i<=n; i++)
        {
            while(scanf("%d",&tmp)&&tmp)
            {
                add(i,tmp);
            }
        }
        solve(n);
    }
    return 0;
}

 

posted @ 2019-07-21 19:22  bluefly-hrbust  阅读(211)  评论(0编辑  收藏  举报