Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 9642 | Accepted: 3832 |
Description
Input
Output
Sample Input
5Sample Output
1
2
/******************************************************************* * 题意:一些学校连成了网络, 在学校之间存在某个协议:每个学校都维护 * 一张传送表,表明他们要负责将收到的软件传送到表中的所有学校。如果A在B的表中, * 那么B不一定在A的表中。 * 现在的任务就是,给出所有学校及他们维护的表,问1、如果所有学校都要被传送到, * 那么需要几份软件备份;2、如果只用一份软件备份,那么需要添加几条边? * * 思路: 这道题就是求学校之间连成网络的强联通分量。第一问中软件只要在一个分量中存在一份,那么分量中的其他学校必然也可以拿到这份软件;第二问中要所有学校都连成一个强联通分量, * 只需要将图中的强联通分量互相之间联通就好了。 * 添加的边数就是缩点后入度为0的点和出度为0的点的最大值。 * * Problem:POJ1236Network of Schools----强连通缩点 * author: sgx * date: 2013/09/07 * 版本: 邻接矩阵,关键用邻接表判断两点间是否有边有点麻烦; *********************************************************************/ #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <algorithm> #define A system("pause") using namespace std; const int maxn=100+5; int map[maxn][maxn]; int dfn[maxn],low[maxn],stack[maxn]; bool instack[maxn]; int indegree[maxn],outdegree[maxn]; int belong[maxn]; int top,Bcnt,index; int m,n; inline int min(int a,int b) { return a<b?a:b; } inline int max(int a,int b) { return a>b?a:b; } void tarjan(int u) { int v; dfn[u]=low[u]=++index; stack[++top]=u; instack[u]=true; for(int i=1;i<=n;i++)//枚举每条边; { if(map[u][i])//找到邻接点; { if(!dfn[i])//若未访问过则访问该点; { tarjan(i); low[u]=min(low[u],low[i]);//树边; } else if(instack[i]) { low[u]=min(low[u],dfn[i]);//后向边; } } } if(dfn[u]==low[u]) { Bcnt++; do { v=stack[top--];//弹出栈顶元素; belong[v]=Bcnt;//标记强连通分量; instack[v]=false; }while(v!=u); } } void solve() { int i; top=index=Bcnt=0; memset(instack,0,sizeof(instack)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(indegree,0,sizeof(indegree)); memset(outdegree,0,sizeof(outdegree)); for(i=1;i<=n;i++) { if(!dfn[i])//如果某点没被访问过,则对其进行tarjan; tarjan(i);//tarjan结果是得到了belong数组,记录每个节点分别属于哪个强联通分量 } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(map[i][j]&&belong[i]!=belong[j])//两点之间有边,但不是属于一个强联通分量的边 { outdegree[belong[i]]++; // 缩点后的点入度+1 indegree[belong[j]]++;// 缩点后的点出度+1 } } } int cnt1=0,cnt2=0; for(int i=1;i<=Bcnt;i++) { if(!indegree[i]) cnt1++; if(!outdegree[i]) cnt2++; } if(Bcnt==1) printf("1\n0\n"); else printf("%d\n%d\n",cnt1,max(cnt1,cnt2)); } int main() { while(scanf("%d",&n)!=EOF) { memset(map,0,sizeof(map)); for(int u=1;u<=n;u++) { int v; while(scanf("%d",&v)&&v) map[u][v]=1; } solve(); } return 0; } /*PS:这个题目第一次接触,A的好艰难,结果最后发现两处错误,Bcnt的初始值设错了 *还有就是少打了个=。。细心啊!!YM下byvoid大牛,讲的很棒~~*/
|