传送门

题意:

  N(2<N<100)个学校之间有单向的网络,每个学校得到一套软件后,可以通过单向网络向周边的学校传输。

  问题1:初始至少需要向多少个学校发放软件,使得网络内所有的学校最终都能得到软件。

  问题2:至少需要添加几条传输线路(边),使任意向一个学校发放软件后,经过若干次传送,网络内所有的学校最终都能得到软件。

从题意中抽象出的算法模型:

  给定一个有向图,求:

  1) 至少要选几个顶点,才能做到从这些顶点出发,可以到达全部顶点。

  2) 至少要加多少条边,才能使得从任何一个顶点出发,都能到达全部顶点。

题解:

  1. 求出所有强连通分量

  2. 每个强连通分量缩成一点,则形成一个有向无环图DAG。

  3. DAG上面有多少个入度为0的顶点,问题1的答案就是多少。

  在DAG上要加几条边,才能使得DAG变成强连通的,问题2的答案就是多少。

  加边的方法:

  要为每个入度为0的点添加入边,为每个出度为0的点添加出边。

  假定有 n 个入度为0的点,m个出度为0的点,如何加边?

  把所有入度为0的点编号 0,1,2,3,4 ....N -1

  每次为一个编号为 i 的入度为0的点到出度为0的点,添加一条出边,这需要加n条边。

  若 m <= n,则

  加了这n条边后,已经没有入度0点,则问题解决,一共加了 n 条边

  若 m > n,则还有m-n个入度0点,则从这些点以外任取一点,和这些点都连上边,即可,这还需加m-n条边。

  所以,max(m,n)就是第二个问题的解

  此外:当只有一个强连通分支的时候,就是缩点后只有一个点,虽然入度出度为0的都有一个,但是实际上不需要增加边了,所以答案是0。

以上解析来源于bin巨%%%%%%

AC代码:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define pb push_back
#define mem(a,b) memset(a,b,sizeof a)
const int maxn=;//最大的节点个数,一般是 1e5 级别的 int scc[maxn];//所属强连通分量的拓扑排序
bool vis[maxn];//vis[u] : dfs中判断节点u是否被访问过
vector<int >vs;//后序遍历顺序的顶点列表
vector<int >edge[maxn],redge[maxn];//边、反边 void addEdge(int u,int v)
{
edge[u].pb(v);
redge[v].pb(u);
}
void Dfs(int u)//第一次dfs,后序遍历标记,越靠近叶子结点标号越小
{
vis[u]=true;
for(int i=;i < edge[u].size();++i)
{
int to=edge[u][i];
if(!vis[to])
Dfs(to);
}
vs.pb(u);
}
void rDfs(int u,int sccId)//反向dfs,利用反向图,求出强连通分量个数
{
vis[u]=true;
scc[u]=sccId;
for(int i=;i < redge[u].size();++i)
{
int to=redge[u][i];
if(!vis[to])
rDfs(to,sccId);
}
}
int Scc(int maxV)
{
mem(vis,false);
vs.clear();
for(int i=;i <= maxV;++i)
if(!vis[i])
Dfs(i);
mem(vis,false);
int sccId=;//DAG节点个数
for(int i=vs.size()-;i >= ;--i)
{
int to=vs[i];
if(!vis[to])
{
sccId++;
rDfs(to,sccId);
}
}
return sccId;//返回强连通分量的个数
}
int main()
{
int N;
scanf("%d",&N);
for(int i=;i <= N;++i)
{
int v;
while(scanf("%d",&v) && v)
addEdge(i,v);
}
int sccId=Scc(N);
int in[maxn];
int out[maxn];
mem(in,);
mem(out,); for(int i=;i <= N;++i)
for(int j=;j < edge[i].size();++j)
{
int to=edge[i][j];
if(scc[i] != scc[to])
out[scc[i]]++,in[scc[to]]++;
}
int zeroIn=;
int zeroOut=;
for(int i=;i <= sccId;++i)
{
zeroIn += (in[i] == ? :);
zeroOut += (out[i] == ? :);
}
printf("%d\n",zeroIn);
if(sccId == )
printf("0\n");
else
printf("%d\n",max(zeroIn,zeroOut));
}

分割线2019.4.27

半年后的我,代码风格:

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define pb(x) push_back(x)
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=+; int n;
int num;
int head[maxn];
struct Edge
{
int to;
int next;
}G[maxn*maxn<<];
void addEdge(int u,int v)
{
G[num]={v,head[u]};
head[u]=num++;
}
struct SCC
{
int col[maxn];
int in[maxn];
int out[maxn];
bool vis[maxn];
vector<int >vs;
void DFS(int u)
{
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(vis[v] || (i&))
continue;
DFS(v);
}
vs.pb(u);
}
void RDFS(int u,int k)
{
col[u]=k;
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(vis[v] || !(i&))
continue;
RDFS(v,k);
}
}
int scc()
{
mem(vis,false);
vs.clear();
for(int i=;i <= n;++i)
if(!vis[i])
DFS(i); int k=;
mem(vis,false);
for(int i=vs.size()-;i >= ;--i)
if(!vis[vs[i]])
RDFS(vs[i],++k); mem(in,);
mem(out,);
for(int u=;u <= n;++u)
{
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(i&)
continue;
if(col[u] != col[v])
{
out[col[u]]++;///col[u]:出度++
in[col[v]]++;///col[v]:入度++
}
}
}
return k;
}
}_scc;
void Solve()
{
int k=_scc.scc(); int zeroIn=;
int zeroOut=;
for(int i=;i <= k;++i)
{
if(!_scc.in[i])
zeroIn++;
if(!_scc.out[i])
zeroOut++;
}
printf("%d\n%d\n",zeroIn,k == ? :max(zeroIn,zeroOut));
}
void Init()
{
num=;
mem(head,-);
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
while(~scanf("%d",&n))
{
Init();
for(int i=;i <= n;++i)
{
int v;
while(scanf("%d",&v) && v)
{
addEdge(i,v);
addEdge(v,i);
}
}
Solve();
}
return ;
}

poj 1236(强连通分量分解模板题)的更多相关文章

  1. POJ(2186)强连通分量分解

    #include<cstdio> #include<vector> #include<cstring> using namespace std; ; vector& ...

  2. poj 2186 强连通分量

    poj 2186 强连通分量 传送门 Popular Cows Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 33414 Acc ...

  3. 算法数据结构 | 三个步骤完成强连通分量分解的Kosaraju算法

    强连通分量分解的Kosaraju算法 今天是算法数据结构专题的第35篇文章,我们来聊聊图论当中的强连通分量分解的Tarjan算法. Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起 ...

  4. 强连通分量分解 Kosaraju算法 (poj 2186 Popular Cows)

    poj 2186 Popular Cows 题意: 有N头牛, 给出M对关系, 如(1,2)代表1欢迎2, 关系是单向的且能够传递, 即1欢迎2不代表2欢迎1, 可是假设2也欢迎3那么1也欢迎3. 求 ...

  5. poj 1904(强连通分量+输入输出外挂)

    题目链接:http://poj.org/problem?id=1904 题意:有n个王子,每个王子都有k个喜欢的妹子,每个王子只能和喜欢的妹子结婚,大臣给出一个匹配表,每个王子都和一个妹子结婚,但是国 ...

  6. poj 2762(强连通分量+拓扑排序)

    题目链接:http://poj.org/problem?id=2762 题意:给出一个有向图,判断任意的两个顶点(u,v)能否从u到达v,或v到达u,即单连通,输出Yes或No. 分析:对于同一个强连 ...

  7. poj 1904(强连通分量+完美匹配)

    传送门:Problem 1904 https://www.cnblogs.com/violet-acmer/p/9739990.html 参考资料: [1]:http://www.cnblogs.co ...

  8. 强连通分量(Tarjan)模板

    贴模板,备忘. 模板1: #include<iostream> #include<cstring> #include<cmath> #include<cstd ...

  9. POJ - 2186  Popular Cows tarjain模板题

    http://poj.org/problem?id=2186 首先求出所有的强连通分量,分好块.然后对于每一个强连通分量,都标记下他们的出度.那么只有出度是0 的块才有可能是答案,为什么呢?因为既然你 ...

随机推荐

  1. Centos6.5网络配置

    由于项目部署的需要,不得不继续研究Linux,前期看过一些Linux方面的资料,也动手配置过Linux网络配置,但是由于开发项目一般在windows下进行的,用Linux比较少,所以基本上也就忘记以前 ...

  2. phpcms全站搜索

    这篇博客已经移至http://www.cnblogs.com/nuanai/p/8028562.html中~~~~~~

  3. win10下安装GLPK

    认识GLPK GLPK是一个解决线性规划问题的工具.是GNU计划下一个用于解线性规 划(Linear Programming)的工具包.它可以方便的描述线性规划问题,并给出相应解. 因此在linux系 ...

  4. 第三个Sprint冲刺第4天

    成员:罗凯旋.罗林杰.吴伟锋.黎文衷 讨论内容:各成员汇报各自完成的情况.

  5. HDOJ2010_水仙花数

    一道水题.一直出现Output Limit Exceeded的原因是在while循环中没有终止条件的时候会自动判断并报错,写的时候忘记加!=EOF结束标识了. HDOJ2010_水仙花数 #inclu ...

  6. TDD中测试替身学习总结

    在使用TDD开发时,经常会遇到需要被测对象需要依赖其他子系统的情况,但是你希望将测试代码跟依赖项隔离,以保证测试代码仅仅针对当前被测对象或方法展开,这时候你需要的是测试替身.测试替身可以分为四类:- ...

  7. phpStorm字体大小无法调整, 怎么办?

    最近上手了一款轻量级IDE phpStorm,可是就在调整编辑器字体大小时却遇到问题了, 发现字体大小无法调整,另外还有字体大小往左还有个“√”,始终无法去掉,这个勾限制了字体系列,就可怜巴巴的那几个 ...

  8. Pandas三个数据结构

    系列(Series) 数据帧(DataFrame) 面板(Panel) 这些数据结构构建在Numpy数组之上,这意味着它们很快. 考虑这些数据结构的最好方法是,较高维数据结构是其较低维数据结构的容器. ...

  9. Delphi学习技巧

    我感觉学习最大的诀窍是, 尽快捕捉到设计者(Delphi VCL 的设计者.进而是 Windows 操作系统的设计者)的某些思路, 和大师的思路吻合了, 才能够融汇贯通, 同时从容使用它们的成果. 碰 ...

  10. python之itemgetter函数:对字典列表进行多键排序

    itemgetter函数:对字典列表进行多键排序 from operator import itemgetter list_people = [ {'name': 'Mike', 'age': 22, ...