P2746

题意翻译成人话就是

求图中连通块中几个点入度为0(也就是没法从根部接受信息,也可以理解成有几个联通块)。

再看任务 B ,显然如果全图连通就是0,我们的目的是将整个图搞成联通,那么统计入度和出度的最小值,就是我们需要添加几个入度才能让整个图连通了。

 

以下是 AC 代码

 

 

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;
inline int read()
{
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int n,a;
struct edge
{
    int nxt,to;
}ed[maxn*30];
int head[maxn*30],cnt;
void add(int a,int b)
{
    ed[++cnt].to = b;
    ed[cnt].nxt = head[a];
    head[a] = cnt;
}
int in[maxn],ot[maxn],id[maxn];
int dfn[maxn],low[maxn],idx,tot;
int stk[maxn],top;
bool instk[maxn];
void tarjan(int s)
{
    dfn[s] = low[s] = ++idx;
    stk[++top] = s;
    instk[s] = true;
    for(int i=head[s];i;i=ed[i].nxt)
    {
        int t = ed[i].to;
        if(!dfn[t])
        {
            tarjan(t);
            low[s] = min(low[s], low[t]);
        }
        else if(instk[t]) low[s] = min(low[s], dfn[t]);
    }
    int k;
    if(dfn[s] == low[s])
    {
        tot ++;
        do{
            k = stk[top--];
            instk[k] = false;
            id[k] = tot;
        }while(k != s);
    }
}
int main()
{
    n = read();
    memset(instk, false, sizeof instk);
    memset(in, 0, sizeof in); memset(ot, 0, sizeof ot);
    for(int i=1;i<=n;i++)
    {
        a = read();
        while(a!=0)
        {
            add(i, a);
            a = read();
        }
    }
    for(int i=1;i<=n;i++)
        if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=ed[j].nxt)
        {
            int t = ed[j].to;
            if(id[t] != id[i])
            {
                ot[id[i]] ++;
                in[id[t]] ++;
            }
        }
    }
    int sum_in = 0, sum_ot = 0;
    for(int i=1;i<=tot;i++)
    {
        if(in[i] == 0)
            sum_in ++;
        if(ot[i] == 0)
            sum_ot ++;
    }
    if(tot == 1)
        printf("1\n0\n");
    else
        printf("%d\n%d\n",sum_in,max(sum_in,sum_ot));
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值