• 题解 P2812 【校园网络【[USACO]Network of Schools加强版】】


    浙江省的几所OI强校的神犇发明了一种人工智能,可以AC任何题目,所以他们决定建立一个网络来共享这个软件。但是由于他们脑力劳动过多导致全身无力身体被♂掏♂空,他们来找你帮助他们。

    共有n所学校(n<=10000)已知他们实现设计好的网络共m条线路,为了保证高速,网络是单向的。现在请你告诉他们至少选几所学校作为共享软件的母机母鸡,能使每所学校都可以用上。再告诉他们至少要添加几条线路能使任意一所学校作为母机母鸡都可以使别的学校使用上软件。

    前置知识:

    分析

    这道题的话,我们先考虑缩短。

    不会缩点的可以看一下我的文章

    既然我们缩好点了,那么整张图变成了一个 (DAG)(有向无环图)

    这样就好处理了。

    • 对于问题 A

      我们发现既然这整张图是 (DAG),那么答案显然为入度为 (0) 的点的个数

    • 对于问题 B
      我们发现这整张图是 (DAG)。我们要把它变成连通图。

      连通图需要满足:

      • 没有入度为 (0) 的点
      • 没有出度为 (0) 的点

      考虑入度为 (0) 和 出度为 (0) 的点两两匹配,则需要匹配 (max{ exttt{入度为} 0 exttt{的点}, exttt{入度为} 1 exttt{的点}) 次。

    一些细节

    注意缩点后只有一个点的情况,本身就是连通的,所以 问题 B 的答案为 (0)

    #include <bits/stdc++.h>
    using namespace std;
    template<typename T>inline void read(T &FF){
    	T RR=1;FF=0;char CH=getchar();
    	for(;!isdigit(CH);CH=getchar())if(CH=='-')RR=-1;
    	for(;isdigit(CH);CH=getchar())FF=(FF<<1)+(FF<<3)+(CH^48);
    	FF*=RR;
    }
    template<typename T>inline void write(T x){
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar('0'+x%10);
    }
    const int MAXN=1e6+10,MAXM=1e6+10;
    int s[MAXN],stop,dfn[MAXN],low[MAXN],scccnt,sccnum[MAXN],dfscnt,tot,he[MAXN],ne[MAXM<<1],ed[MAXM<<1],n,x,se,es,du[MAXN],ud[MAXN];
    void add(int x,int y){
    	ed[++tot]=y;
    	ne[tot]=he[x];
    	he[x]=tot;
    }
    inline void tarjan(int now){
    	dfn[now]=low[now]=++dfscnt;
    	s[stop++]=now;
    	for (int i=he[now];i;i=ne[i]){
    		if(!dfn[ed[i]]){
    			tarjan(ed[i]);
    			low[now]=min(low[now],low[ed[i]]);
    		}else if(!sccnum[ed[i]]){
    			low[now]=min(low[now],dfn[ed[i]]);
    		}
    	}
    	if(dfn[now]==low[now]){
    		scccnt++;
    		do{
    			sccnum[s[--stop]]=scccnt;
    		}while(s[stop]!=now);
    	}
    }//tarjin的板子
    int main(){
    	read(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])tarjan(i);
    	for(int i=1;i<=n;i++)
    		for(int j=he[i];j;j=ne[j])
    			if(sccnum[i]!=sccnum[ed[j]]){
    				du[sccnum[ed[j]]]++;//统计
    				ud[sccnum[i]]++;//统计
    			}
    	for(int i=1;i<=scccnt;i++){
    		if(!du[i])se++;//入度为0的点
    		if(!ud[i])es++;//出度为0的点
    	}
    	cout<<se<<endl<<(scccnt==1?0:max(se,es));//小细节
    	return 0;
    }
    
  • 相关阅读:
    strpos 判断字符串是否存在
    TP 自动验证
    label 标签的用法,点label选中单选、复选框或文本框
    str_replace 替换 小技巧
    数据库文件MDF的空间占满了,没有自动增长是怎么回事?
    (4.7)mysql备份还原——深入解析二进制日志(3)binlog的三种日志记录模式详解
    (4.6)mysql备份还原——深入解析二进制日志(2)binlog参数配置解析
    (1.16)mysql server优化之buffer pool
    COALESCE函数
    linux网络设置和虚拟机克隆转移之后网卡找不到
  • 原文地址:https://www.cnblogs.com/zhaohaikun/p/13830086.html
Copyright © 2020-2023  润新知