洛谷P2746 [USACO5.3]校园网Network of Schools 强连通分量

题目链接:https://www.luogu.com.cn/problem/P2746

任务A:求最少的接受软件的学校数目,能使所有学校都能用到软件。
任务B:求最少扩展几个学校,能使从任意学校发软件可以使所有学校用到。
我们抽象成图,任务A就变成选择最少几个点能遍历全图任务B就变成加几条边,能使整个图变成强连通分量
我们可以知道,任意一个强连通分量里的点是互相可达的,所以我们先用tarjan缩点,把整个图简化成点不使互相可达的。
现在,我们再看任务A,我们要选择几个点,或者要选择哪几个点?我们从出度入度的角度考虑,如果一个点入度为0,那么其它点到达不了它,它就必须被选择,如果一个点入度不为0,那么肯定有学校下发软件给它,它就不用被选择,所以我们只要选入度为0的点即可。任务A的答案就是图上入度为0的点的数量了。
我们再看任务B,我们要加几条边呢,或者我们要加哪几条边呢。我们再从入度出度的角度考虑,一个点能被其它点传送信息,它的入度就必须不是0,如果一个点能传送信息给其它点,那么它的出度就必须不是0,当我们加一条边时,一个点的入度+1,一个点的出度+1,我们最少要加**max(入度为0点的数量,出度为0的点的数量)**才能让所有点能被传递信息,并且能传递信息给其他点,这样就是尽可能构成一个环。任务B的答案就就是max(入度为0点的数量,出度为0的点的数量),当然只有一个点时除外,因为它不需要被别人传递信息或者传递信息给别人,这个特判一下,答案是0。

#include <bits/stdc++.h>
using namespace std;
const int maxn=102;
struct node
{
    int to,next;
}p[maxn*maxn];
int dfn[maxn],low[maxn];
int col[maxn],fa[maxn];
int head[maxn];
int cnt,dfn_num,col_id;
void add(int x,int y)
{
    p[++cnt].next=head[x];
    p[cnt].to=y;
    head[x]=cnt;
}
int stc[maxn];//模拟栈
bool vis[maxn];//标记是否在栈中
int top;
void tarjan(int u)
{
   vis[u]=1;
   dfn[u]=low[u]=++dfn_num;
   stc[++top]=u;
   for(int i=head[u];i;i=p[i].next)
   {
        int v=p[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(vis[v])
        low[u]=min(low[u],dfn[v]);
   }
   if(dfn[u]==low[u])
   {
        vis[u]=false;
        col[u]=++col_id;
        while(stc[top]!=u)
        {
            vis[stc[top]]=false;
            col[stc[top--]]=col_id;
        }
        top--;
   }
}
int n;
int indeg[maxn],outdeg[maxn];//入度与出度
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int y;
        while(~scanf("%d",&y)&&y)
        {
            add(i,y);
        }
    }
    for(int i=1;i<=n;i++)
    if(!dfn[i])
    tarjan(i);
    if(col_id==1)//只有一个强连通分量
    {
        puts("1");
        puts("0");
        return 0;
    }
    for(int i=1;i<=n;i++)
    for(int j=head[i];j;j=p[j].next)
    {
        int v=p[j].to;
        if(col[i]!=col[v])
        indeg[col[v]]++,outdeg[col[i]]++;
    }
    int a=0,b=0;//入度为0的数量与出度为0的数量
    for(int i=1;i<=col_id;i++)
    {
        if(!indeg[i])
        a++;
        if(!outdeg[i])
        b++;
    }
    printf("%d\n",a);
    printf("%d\n",max(a,b));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44491423/article/details/104554485
今日推荐