题目大意

有N个学校,这些学校之间用一些单向边连接,若学校A连接到学校B(B不一定连接到A),那么给学校A发一套软件,则学校B也可以获得。现给出学校之间的连接关系,求出至少给几个学校分发软件,才能使得所有的学校均可以获得软件;以及,至少需要添加几条单向边连接学校,才能使得给这些学校中任何一所发软件,其余的学校均可以收到。

题目分析

在一个图中,强连通分支内的任何一个点被“发软件”,则分支内的所有点均可以获得,因此首先求出强连通分支,将强连通分支合并为一点来看。 
    重构之后的图若只有一个点,则只需要向任何一所学校发送即可。即结果为1(至少向1所学校发布软件) 0(不需要添加新边来使得整个图连通). 
    重构之后的图若有多个点,则考虑这些点中入度为0的点:入度为0的点不能被其他点到达,而一个入度不为0的点可以从某个入度为0的点到达,那么只需要向这些入度为0的点分发软件,就可以使得所有的点均能获得软件。 
    重构之后的图中有出度为0的点,在图中,入度为0的点(设为m个)无法从其他点到达,那么为了使得所有的点连通,需要m条路径连接到这m个入度为0的点;而出度为0的点(设为n个)无法到达其他点,那么为了使得所有的点连通,需要n条路径从这n个出度为0的点连出。于是,至少需要添加 max(m, n)条边,使得图中所有的点的入度和出度不为0. 
    同时,在一个有向无环图中,如果该图的所有点均可连接到一块,且每个点的出度和入度均不为0,则该图肯定强连通。于是,结果为 max(m,n)

实现(c++)

#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>
#include<set>
#define MAX_NODE 105
#define min(a, b) a < b? a:b
#define max(a, b) a > b? a:b
using namespace std;
vector<vector<int> > gGraph; //存储图结构
stack<int> gStack; //用于Tarjan算法 bool gVisited[MAX_NODE]; //判断每个点是否被访问过
bool gInStack[MAX_NODE]; //在Tarjan算法中判断点是否在栈中
int gDfn[MAX_NODE]; //Tarjan算法中标记每个点最开始被访问的时间
int gLow[MAX_NODE]; //Tarjan算法中标记从每个点开始的DFS过程中经过的点所能访问到的点的最小的开始时间 int gClusterOfNode[MAX_NODE]; //标记每个点所在的强连通分支
int gIndex; //标记点被第一次访问的时间
int gClusterIndex; //强连通分支的编号 //Tarjan算法求强连通分支
void Tarjan(int u){
gLow[u] = gDfn[u] = ++gIndex;
gVisited[u] = true;
gInStack[u] = true;
gStack.push(u); for (int i = 0; i < gGraph[u].size(); i++){
int v = gGraph[u][i];
if (!gVisited[v]){
Tarjan(v);
gLow[u] = min(gLow[u], gLow[v]);
}
else if (gInStack[v]){
gLow[u] = min(gLow[u], gDfn[v]);
}
}
if (gLow[u] == gDfn[u]){
int v;
do{
v = gStack.top();
gStack.pop();
gInStack[v] = false;
gClusterOfNode[v] = gClusterIndex; //标记所属的强连通分支编号
} while (v != u);
gClusterIndex++;
}
}
vector<set<int> > gLinkTo; //将强连通分支缩成点之后,每个点所连接到的另外的点,用set 使得插入时不重复。用于统计出度
vector<set<int> > gLinkFrom; //将强连通分支缩成点之后,每个点被其他的点连接,用set 使得插入时不重复。用于统计入度 //将强连通分支缩成点,然后统计每个强连通分支的入度和出度
void ReconstructGraph(int nodes, int clusters){
gLinkTo.resize(clusters);
gLinkFrom.resize(clusters); for (int u = 1; u <= nodes; u++){
for (int i = 0; i < gGraph[u].size(); i++){
int v = gGraph[u][i];
int uc = gClusterOfNode[u];
int vc = gClusterOfNode[v];
if (uc != vc){ //注意!!!自身不能连接到自身!
gLinkTo[uc].insert(vc);
gLinkFrom[vc].insert(uc);
}
}
}
} int main(){
int n, u, v;
scanf("%d", &n);
gGraph.resize(n + 1);
for (int i = 1; i <= n; i++){
while (scanf("%d", &v) && v != 0){
gGraph[i].push_back(v);
}
}
gIndex = gClusterIndex = 0;
memset(gVisited, false, sizeof(gVisited));
memset(gInStack, false, sizeof(gInStack));
for (int u = 1; u <= n; u++){
if (!gVisited[u]){
Tarjan(u);
}
}
ReconstructGraph(n, gClusterIndex);
int zero_outdegree = 0, zero_indegree = 0;
for (int i = 0; i < gClusterIndex; i++){
if (gLinkFrom[i].empty()){
zero_indegree++;
}
if (gLinkTo[i].empty()){
zero_outdegree++;
}
}
if (gClusterIndex == 1){ //如果只有一个强连通分支,则直接输出1 0
printf("1\n0\n");
}else
//最少需要发送的版本个数,等于将强连通分支缩成点之后的图中 入度为0的点的个数,
//因为,一个有向无环图中,所有入度不为0的点,一定可以从某个入度为0的点出发可达。
//而这些入度为0的点之间不能可达,故至少需要将所有这些入度为0的点设为起点 //需要连接多少条有向边才能使得整个图称为一个强连通图
//入度为0的点设为m个,不能被其他任何点可达,因此,要有 m条边连接到 这m个入度为0的点
//出度为0的点设为n个,无法到达其他点,因此要有n条边从这n个出度为0的点连接出去
//可以证明,在一个有向无环图中,所有点的入度和出度均不为0,则该图为强连通的
//则,至少有 max(m, n)条边。 printf("%d\n%d\n", zero_indegree, max(zero_outdegree, zero_indegree));
return 0;
}

poj_1236 强连通分支的更多相关文章

  1. Kosaraju 算法查找强连通分支

    有向图 G = (V, E) 的一个强连通分支(SCC:Strongly Connected Components)是一个最大的顶点集合 C,C 是 V 的子集,对于 C 中的每一对顶点 u 和 v, ...

  2. poj 2553 强连通分支与缩点

    思路:将所有强连通分支找出来,并进行缩点,然后找其中所有出度为0的连通分支,就是题目要求的. #include<iostream> #include<cstdio> #incl ...

  3. poj 2186 强连通分支 和 spfa

    思路: 建图时,分别建正向图edge和转置图T.用正向图edge来DFS,找出第一个被发现的强连通分支(如果该图存在题目要求的点,那么一定就是第一个被发现的).然后用spfa跑转置图T,判断被发现的点 ...

  4. poj 1236 Network of Schools【强连通求孤立强连通分支个数&&最少加多少条边使其成为强连通图】

    Network of Schools Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 13800   Accepted: 55 ...

  5. 基于visual Studio2013解决算法导论之050强连通分支

     题目 强连通分支 解决代码及点评 // 强连通分支.cpp : 定义控制台应用程序的入口点. // #include<iostream> #define MAX 100 using ...

  6. 有向图强连通分支的Tarjan算法讲解 + HDU 1269 连通图 Tarjan 结题报告

    题目很简单就拿着这道题简单说说 有向图强连通分支的Tarjan算法 有向图强连通分支的Tarjan算法伪代码如下:void Tarjan(u) {dfn[u]=low[u]=++index//进行DF ...

  7. poj_2553 强连通分支&出度为0的点

    题目大意 N个点的有向图中,定义“好点”为: 从该点v出发可以到达的所有点u,均有一条路径使得u可达v. 求出图中所有的“好点”,并按照顺序从小到大输出出来. 题目分析 图存在多个强连通分支,强连通分 ...

  8. poj_2186 强连通分支

    题目大意 有N头牛,他们中间有些牛会认为另外一些牛“厉害”,且这种认为会传递,即若牛A认为牛B“厉害”,牛B认为牛C“厉害”,那么牛A也认为牛C“厉害”.现给出一些牛的数对(x, y)表示牛x认为牛y ...

  9. 割点与桥,强连通分量,点双,边双[poj_1236]学校网络

    割点与桥 题目描述 给定一张无向图G(V,E),你需要找出所有的割点与桥. 输入 第一行给出两个正整数V,E. 接下来E行每行两个正整数x,y,表示有一条连接x,y的边. 输出 输出共2行,第一行输出 ...

随机推荐

  1. 【C#】访问泛型中的List列表数据

    光看标题的确不好说明问题,下面描述一下问题场景: 已知后端自定义的返回的Json数据结构如下: response: { "message": "返回成功", & ...

  2. 【WPF】MVVM前台绑定一组RadioButton按钮

    需求:制作一组RadioButton,像下面这样的效果: [MVVM]要显示一组RadioButton按钮,想法是Controller层联网获取到数据后,将数据进行处理,然后加到一个Observabl ...

  3. java并发编程()阻塞方法与中断方法

    看完这篇,我感觉我对java多线程又懵逼了. 线程可能会阻塞或暂停执行,原因有多种: 等待I/O操作结束 等待获得一个锁 等待从Thread.sleep方法中醒来 等待另一个线程计算的结果 当线程阻塞 ...

  4. Spring事务处理时自我调用的解决方案 嵌套AOP

    开涛的解决方案1 http://jinnianshilongnian.iteye.com/blog/1487235 AopContext.currentProxy() 原理 http://books. ...

  5. linux内存查看及释放

    查看内存 常用的查看内存工具有:top,ps,free,/proc/meminfo,/proc/$PID/status等,一般都指定了虚拟内存占用情况,但ps或/proc/$PID/status中RS ...

  6. 一站式学习Wireshark(七):Statistics统计工具功能详解与应用

    Wireshark一个强大的功能在于它的统计工具.使用Wireshark的时候,我们有各种类型的工具可供选择,从简单的如显示终端节点和会话到复杂的如Flow和IO图表.本文将介绍基本网络统计工具.包括 ...

  7. eclipse安装中文补丁包

    第一步:打开http://www.eclipse.org/babel/ 第二步:找到downloads. 第三步:点击Oxygen. 第四步:找到简体中文的zip插件并兵下载. 第五步:解压. 第六步 ...

  8. tomcat7项目启动报错java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory

     报这个错说明用的是tomcat7 打开myeclipse,Preferentces->MyEclipse->Servers->Tomcat->Tomcat 6.x ,载入 ...

  9. 【3C认证】安防产品3C认证

    安防产品3C认证作为3C认证的一部分.安防产品即:防范的手段达到或实现安全的目的的设备或器材. 依据<中华人民共和国产品质量法>.<中华人民共和国标准化法>.<中华人民共 ...

  10. Web API(三):创建Web API项目

    在本篇文章中将讲解如何使用Visual Studio创建一个新的ASP.NET Web API项目. 在Visual Studio中有两种方式用于创建Web API项目: 1.创建带MVC的Web A ...