• P2812 校园网络


    luogu 传送门

    首先考虑问题一


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

    然后考虑问题二

    “任意一个学校都能作为母鸡”?试想一下,任意选取一个学校作为终端,要使得其余所有学校都能收到,只能是全图联通。因此,当且仅当我们将所有出度为0的缩点连向所有入度为0的缩点时,可以使全图联通且+边最小。于是将出度为0的缩点和入度为0的缩点的个数取max就好了。

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

    #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
    %d", ans1, max(ans1, ans2));//记得要取max(虽然luogu的数据不取max好像也能水过去)
        return orz;         //%一下CCF求AC 
    }
  • 相关阅读:
    通过在vs中”程序包管理器控制台“的输入命令来实现下载和安装所需版本的Mysql.data和Mysql.Data.Entity.EF6
    ireport使用问题
    mysql数据库迁移到达梦数据库
    Idea配置热部署
    阿里云双12年终钜惠
    移动端弹性布局方案lib-flexible实践
    阿里云服务器2折起
    javascript百度地图使用(根据地名定位、根据经纬度定位)
    js拖拽上传图片
    javascript xml转json
  • 原文地址:https://www.cnblogs.com/wondering-world/p/12634425.html
Copyright © 2020-2023  润新知