标签:
http://poj.org/problem?id=1236
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 13046 | Accepted: 5215 |
Description
Input
Output
Sample Input
5 2 4 3 0 4 5 0 0 0 1 0
Sample Output
1 2
题目大意:
一些学校连成了网络, 在学校之间存在一 个协议:每个学校都维护一张传送表,表明他们要负责将收到的软件传送到表中的所有学校。如果A在B的表中,那么B不一定在A的表中。
现在的任务就是,给出所有学校及他们维护的表,问1、如果所有学校都要被传送到,那么需要几份软件备份;2、如果只用一份软件备份,那么需要添加几条边?
分析:
问题1:找入度为0的点的个数
问题2:找入度为0的个数与出度为0的个数的最大值
#include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> #include<vector> #include<algorithm> #define N 110 using namespace std; vector<vector<int> >G; int low[N], dfn[N], di[N], maps[N][N]; int Stack[N], n, top, Time, cnt; bool Instack[N]; void Init() { G.clear(); G.resize(n + 1); memset(low, 0, sizeof(low)); memset(dfn, 0, sizeof(dfn)); memset(Stack, 0, sizeof(Stack)); memset(di, 0, sizeof(di)); memset(Instack, false, sizeof(Instack)); Time = top = cnt = 0; } void Tarjan(int u) { int i, v, len; low[u] = dfn[u] = ++Time; Stack[top++] = u;//进栈 Instack[u] = true; len = G[u].size(); for(i = 0 ; i < len ; i++)//遍历入栈节点的边 { v = G[u][i]; if(!dfn[v])//点v未被访问过则则对其进行Tarjan { Tarjan(v); low[u] = min(low[u], low[v]);// 回溯的时候改变当前节点的low值 } else if(Instack[v])//如果新搜索到的节点已经被搜索过而且现在在栈中 low[u] = min(low[u], dfn[v]);//更新当前节点的low值,这里的意思是两个节点之间有一条可达边,而前面节点已经在栈中,那么后面的节点就可能和前面的节点在一个联通分量中 } if(dfn[u] == low[u])//最终退回来的时候 low == dfn , 没有节点能将根节点更新,那 low == dfn 的节点必然就是根节点 { do { v = Stack[--top];//出栈 Instack[v] = false; di[v] = cnt;//表示点v在第cnt个强联通分量里 } while(v != u); //一直出栈到此节点, 这些元素是一个强联通分量 cnt++;//联通分量的个数 } }//Tarjan的记过得到di数组记录每个节点分别属于哪个强联通分量 void Solve() { int i, j, In[N], Out[N], in = 0, out = 0; memset(In, 0, sizeof(In)); memset(Out, 0, sizeof(Out)); for(i = 1 ; i <= n ; i++) if(!low[i]) Tarjan(i); for(i = 1 ; i <= n ; i++)// 遍历每条边,找到缩点之后的边 { for(j = 1 ; j <= n ; j++) { if(i == j) continue; if(maps[i][j] && di[i] != di[j])//如果i,j两点有边且不属于一个联通分量的边 { Out[di[i]]++;//缩点后出度+1 In[di[j]]++;//缩点后入读+1 } } } for(i = 0 ; i < cnt ; i++) { if(!In[i]) in++; if(!Out[i]) out++; }//in表示入度为0的点的个数,out表示出度为0的点的个数 if(cnt == 1)//注意当联通分量只有一个时,不应该加边 printf("1\n0\n"); else printf("%d\n%d\n", in, max(in, out)); } int main() { int i, a; while(~scanf("%d", &n)) { Init(); for(i = 1 ; i <= n ; i++) { while(scanf("%d", &a), a) { G[i].push_back(a); maps[i][a] = 1; } } Solve(); } return 0; }
poj 1236 Network of Schools(连通图入度,出度为0)
标签:
原文地址:http://www.cnblogs.com/qq2424260747/p/4708974.html