• 校园网络 luogu P2812 (又是强联通)


    题目传送门!(luogu)

    首先考虑问题一


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

    然后考虑问题二

    “任意一个学校都能作为母鸡”?试想一下,任意选取一个学校作为终端,要使得其余所有学校都能收到,只能是全图联通。因此,找到出度为0和入度为0的缩点的个数取max就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++;//统计 
        }
        if(cnt == 1) printf("1
    0");  /*记得特判呀*/ 
        else printf("%d
    %d", ans1, max(ans1, ans2));
        return orz;         //%一下CCF求AC 
    }
  • 相关阅读:
    jms学习笔记
    UML类图与类的关系详解
    javolution学习--介绍
    Eclipse中10个最有用的快捷键组合
    [疯狂Java]JDBC:PreparedStatement预编译执行SQL语句
    Oracle OLAP 与 OLTP 介绍
    DRDS SQL兼容性
    DRDS 概述
    跨时代的分布式数据库 – 阿里云DRDS详解(转)
    java.net.UnknownHostException: www.terracotta.org
  • 原文地址:https://www.cnblogs.com/wondering-world/p/12710228.html
Copyright © 2020-2023  润新知