NYOJ-120校园网络【强连通分量缩点&&tarjan】
2014-12-17 20:57
225 查看
校园网络
时间限制:3000 ms | 内存限制:65535 KB难度:5
描述
南阳理工学院共有M个系,分别编号1~M,其中各个系之间达成有一定的协议,如果某系有新软件可用时,该系将允许一些其它的系复制并使用该软件。但该允许关系是单向的,即:A系允许B系使用A的软件时,B未必一定允许A使用B的软件。
现在,请你写一个程序,根据各个系之间达成的协议情况,计算出最少需要添加多少个两系之间的这种允许关系,才能使任何一个系有软件使用的时候,其它所有系也都有软件可用。
输入第一行输入一个整数T,表示测试数据的组数(T<10)
每组测试数据的第一行是一个整数M,表示共有M个系(2<=M<=100)。
随后的M行,每行都有一些整数,其中的第i行表示系i允许这几个系复制并使用系i的软件。每行结尾都是一个0,表示本行输入结束。如果某个系不允许其它任何系使用该系软件,则本行只有一个0.
输出对于每组测试数据,输出最少需要添加的这种允许关系的个数。
样例输入
1 5 2 4 3 0 4 5 0 0 0 1 0
样例输出
2
像上面的有向图。因为强连通分量中任意两点可以通过某条路径连通,也就是说某个点有新软件可用,强连通分量中的其它点必定可通过传递来使用,所以把所有强连通分量视为一个点。至于加边,就是把强连通分量缩点后的图变成环。只需要寻找入度为0的点和出度为0的点,两者中数量最大值即为答案。
有两种求强连通分量的算法。
(1)可以通过两次简单的DFS实现。第一次DFS时,选取任意顶点,作为起点,遍历所有尚未访问过的顶点,并在回溯前给顶点标号(后序遍历)。完成标号后,将所有边反向,然后以标号最大的顶点作为起点DFS。这样DFS所遍历的顶点集合就变成了一个强连通分量。之后,只要还有尚未访问的顶点,就从中选取标号最大的顶点不断重复上述过程。
(2)tarjan算法:Tarjan算法基于定理:在任何深度优先搜索中,同一强连通分量内的所有顶点均在同一棵深度优先搜索树中。也就是说,强连通分量一定是有向图的某个深搜树子树。
可以证明,当一个点既是强连通子图Ⅰ中的点,又是强连通子图Ⅱ中的点,则它是强连通子图Ⅰ∪Ⅱ中的点。
这样,我们用low值记录该点所在强连通子图对应的搜索子树的根节点的Dfn值。注意,该子树中的元素在栈中一定是相邻的,且根节点在栈中一定位于所有子树元素的最下方。强连通分量是由若干个环组成的。所以,当有环形成时(也就是搜索的下一个点已在栈中),我们将这一条路径的low值统一,即这条路径上的点属于同一个强连通分量。
如果遍历完整个搜索树后某个点的dfn值等于low值,则它是该搜索子树的根。这时,它以上(包括它自己)一直到栈顶的所有元素组成一个强连通分量。
#include <stdio.h> #include <string.h> #include <stack> #define Minn(a,b) a>b?b:a #define Maxn(a,b) a>b?a:b using namespace std; int M; bool map[106][106];//用邻接矩阵来存边方便计算出入度 bool mark[106];//标记数组 int d[300]; int p[106]; int low[106]; int dfn[106]; int num; int count; int inum,onum;//入度为0的点 出度为0的点 stack<int> sta; void tarjan(int x)//tarjan算法 { int i; low[x]=dfn[x]=++count; sta.push(x); mark[x]=1; for(i=1;i<=M;i++) { if(map[x][i]==1) { if(!dfn[i]) { tarjan(i); low[x]=Minn(low[x],low[i]); } else if(mark[i]==1) low[x]=Minn(low[x],dfn[i]); } } if(low[x]==dfn[x]) {//我把所有栈里弹出的属于同一强连通分量的点都编号为num,++num可以使不同强连通分量的编号不同。 int v; int t=++num; do {//弹出的点暂时存在d数组中。p数组存储该点所属的强连通分量的编号 v=sta.top();sta.pop();mark[v]=0; d[t++]=v;p[v]=num; }while(low[v]!=dfn[v]); if(t-num==M)//如果说图就是个强连通图直接返回。 return; int id=0,od=0; for(t=t-1;t>=num;t--) {//邻接矩阵里计算该强连通缩点的出入度 v=d[t]; for(i=1;i<=M;i++) { if(map[v][i]==1&&p[v]!=p[i]) od++; if(map[i][v]==1&&p[v]!=p[i]) id++; } } if(od==0) onum++; if(id==0) inum++; } } int main() { int T; int i; int ch; int ans; scanf("%d",&T); while(T--) { scanf("%d",&M); memset(map,0,sizeof(map)); for(i=1;i<=M;i++) { scanf("%d",&ch); while(ch!=0) {map[i][ch]=1;scanf("%d",&ch);} } memset(dfn,0,sizeof(dfn)); memset(mark,0,sizeof(mark)); memset(p,0,sizeof(p)); count=0;num=0; inum=onum=0; for(i=1;i<=M;i++) { if(!dfn[i]) tarjan(i); } ans=Maxn(inum,onum); printf("%d\n",ans); } return 0; }
相关文章推荐
- NYOJ-120 校园网络 &&POJ 1236 (强连通缩点targan算法)
- 强连通Tarjan NYOJ 120 校园网络
- NYOJ 120 校园网络(强连通缩点)
- NYOJ-120 校园网络(强连通缩点targan算法)
- nyoj 120 校园网络(入度出度判断)
- NYOJ 120 校园网络
- nyoj120校园网络_强连通问题
- nyoj120 校园网络(强连通+缩点)
- nyoj--120--校园网络(scc+缩点)
- NYOJ120 校园网络(强联通)
- 【强连通分量】nyoj120 校园网络(模板题)
- NYOJ 120-校园网络
- nyoj 120 校园网络
- nyoj 120 校园网络 【强连通】
- NYOJ120 校园网络(强联通)
- NYOJ-120 校园网络 强连接
- NYOJ120 校园网络 强连通缩点
- NYOJ 120 校园网络
- nyoj 120 校园网络(求添加多少条边使整个图强连通)
- NYOJ 120 校园网络