码迷,mamicode.com
首页 > 其他好文 > 详细

P2812 校园网络

时间:2020-04-04 22:52:19      阅读:85      评论:0      收藏:0      [点我收藏+]

标签:个数   ret   i++   一个   getchar   add   fine   nbsp   struct   

https://www.luogu.com.cn/problem/P2812  传送门

 

首先考虑问题一


不难想到,如果有一个学校作为终端机,那么跟其处于同一个强联通中的所有学校就可以不用作为终端机了。 那么,问题一也就迎刃而解了:找到所有入度为0的缩点。因为这个学校(强联通中至少有一个学校)必须作为终端机,毕竟它收不到别的学校传来的,只能自给自足。

然后考虑问题二

“任意一个学校都能作为母鸡”?试想一下,任意选取一个学校作为终端,要使得其余所有学校都能收到,只能是全图联通。因此,找到出度为0的缩点的个数就ok了。(即从出度为0的点连向入度为0 的点)

不废话,上代码。细节已标好

 

#include <bits/stdc++.h>
using namespace std;
#define N 5000010
#define orz 0

inline int read(){
    int x = 0, s = 1;
    char c = getchar();
    while(!isdigit(c)){
        if(c == -)s = -1;
        c = getchar();
    }
    while(isdigit(c)){
        x = (x << 1) + (x << 3) + (c ^ 0);
        c = getchar();
    }
    return x * s;
} 

struct node{
    int u, v;
    int next;
} t[N];
int f[N];//日常邻接表 

int stac[N], top = 0;
int dfn[N], scc[N], low[N];
bool vis[N];
//tarjan 板子,不多说 
int in[N], out[N];//入度出度 
int ans1 = 0, ans2 = 0;

int bian = 0;
inline void add(int u, int v){
    t[++bian].v = v;
    t[bian].u= u;
    t[bian].next = f[u];
    f[u] = bian;
    return ;
}

int cac = 0, cnt = 0;
void tarjan(int now){//有向图强联通板子 
    dfn[now] = low[now] = ++ cac;
    stac[++top] = now;
    vis[now] = 1;
    for(int i = f[now]; i;i = t[i].next){
        int v = t[i].v;
        if(!dfn[v]){
            tarjan(v);
            low[now] = min(low[now], low[v]);
        }
        else if(vis[v])low[now] = min(low[now], dfn[v]);
    }
    if(dfn[now] == low[now]){
        int cur; 
        cnt++;
        do{
            cur = stac[top--];
            vis[cur] = 0;
            scc[cur] = cnt;
        }while(cur != now);
    }
    return ;
}

int main(){
    int n = read();
    for(int i = 1;i <= n; i++){
        int x = read();
        while(x){
            add(i, x);
            x = read();
        }
    }
    for(int i = 1;i <= n;i++)
        if(!dfn[i]) tarjan(i);//注意防止有的点漏掉 
    for(int i = 1;i <= bian; i++){ //统计所有的边 
        int u = t[i].u, v = t[i].v;
        if(scc[u] != scc[v]){//如果起点和终点不在同一个缩点  (即在两个缩点的交界处的边) 
            out[scc[u]]++;
            in[scc[v]]++;
        }

    }
    for(int i = 1;i <= cnt; i++){
        if(!in[i])ans1++;
        if(!out[i])ans2++;//统计 
    }
    printf("%d\n%d", ans1, ans2);
    return orz;         //%一下CCF求AC 
}

 

P2812 校园网络

标签:个数   ret   i++   一个   getchar   add   fine   nbsp   struct   

原文地址:https://www.cnblogs.com/wondering-world/p/12634425.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!