Poj 1236 : 有向图 :缩点+求强连通

题目链接

题意:

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

题解:

首先我们利用 tarjan 求出该有向图中的强连通分量,对强连通分量,进行缩点,然后在缩点图里,枚举每条边所连的点的入度和出度,如果两个点是同一强连通分量里的点,就不计算。第一个问题,我们只需要,求出没有入度的点的数量即可,第二个问题,我们要构造强连通图,所以每个点都会有入度和出度,所以我们只要求出没有入度和出度的点数量的最大值即可,让这些点相连,即可构造强连通图。

写题时遇到的问题:

以前我总迷惑,这里用 ++toptop++ 有啥区别,今天好好思考了一下,原来用 ++top的话,下放用top++的缩点方式会有问题,当是单点的时候,top不会 – 这个问题,最终导致答案会出现异常。

在这里插入图片描述

AC代码:

#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1e6+5;
#define ll long long
struct node
{
    int to,nex;
} edge[maxn<<1];
int cnt,cnx,top,tim;
int head[maxn],dfn[maxn],low[maxn],in[maxn];
int stac[maxn],instac[maxn],sg[maxn],ou[maxn];
void add(int u,int v)
{
    edge[cnt].to=v;
    edge[cnt].nex=head[u];
    head[u]=cnt++;
}
void dfs(int u)
{
    dfn[u]=low[u]=++tim;
    stac[top++]=u;
    instac[u]=1;
    for(int i=head[u]; ~i; i=edge[i].nex)
    {
        int v=edge[i].to;
        if(!dfn[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if(instac[v])
        {
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(dfn[u]==low[u])
    {
        cnx++;
        while(top>0&&stac[top]!=u)
        {
            top--;
            int x=stac[top];
            sg[x]=cnx;
            instac[x]=0;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    memset(head,-1,sizeof(head));
    int n,x;
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        while(cin>>x&&x)
        {
            add(i,x);
        }
    }
    for(int i=1; i<=n; i++)
    {
        if(!dfn[i])
        {
            dfs(i);
        }
    }
    if(cnx==1)
    {
        cout<<1<<'\n'<<0<<endl;
        return 0;
    }
    for(int i=1; i<=n; i++)
    {
        for(int j=head[i]; ~j; j=edge[j].nex)
        {
            int v=edge[j].to;
            if(sg[i]!=sg[v])
            {
                in[sg[v]]++;
                ou[sg[i]]++;
            }
        }
    }
    int ix,ox;
    ix=ox=0;
    for(int i=1; i<=cnx; i++)
    {
        if(!in[i])
        {
            ix++;
        }
        if(!ou[i])
            ox++;
    }
    cout<<ix<<'\n'<<max(ix,ox)<<endl;
}

发布了254 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/104485316
今日推荐