校园网络

来源:互联网 发布:虎嗅网源码下载 编辑:程序博客网 时间:2024/04/27 10:30

算法:连通图

描述
南阳理工学院共有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

代码:

//连通图 #include <iostream>#include <cstring>#include <algorithm>#include <iomanip>#include <stack>using namespace std;#define Max 105int In[Max],Out[Max],map[Max][Max],Instack[Max];int DFN[Max],LOW[Max],t[Max];int n,res,loer,ans;stack<int>s;void cmp(){memset(In,0,sizeof(In));//索点后记录入度 memset(Out,0,sizeof(Out));//记录出度 memset(Instack,0,sizeof(Instack));//标记是否进栈 memset(map,0,sizeof(map));//记录边的关系 memset(DFN,0,sizeof(DFN)); //辅助数组求连通分量memset(LOW,0,sizeof(LOW));// 辅助数组求连通分量memset(t,0,sizeof(t));//记录该点所属第几个连通分量; res=0;loer=0;//res统计连通分量数, }void tr(int u){DFN[u]=LOW[u]=++loer;//记下是第几个进栈的,//LOW 记录s.push(u);Instack[u]=1;for(int i=1;i<=n;i++){if(map[u][i]){if(!DFN[i]){tr(i);LOW[u]=min(LOW[u],LOW[i]); }else if(Instack[i])    LOW[u]=min(LOW[u],DFN[i]);}}int v;if(DFN[u]==LOW[u]){++res; do{v=s.top();s.pop();Instack[v]=0;t[v]=res;}while(v!=u); }}void tarjan(){for(int i=1;i<=n;i++)if(!DFN[i])    tr(i);}void sovle(){for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)if(map[i][j]){++In[t[i]];++Out[t[j]];}}int xx=0,yy=0;for(int i=1;i<=res;i++){if(In[i]==0)xx++;if(Out[i]==0)yy++;} ans=xx>yy?xx:yy;}int main(){int i,j,k,m,T;cin>>T;while(T--){cmp();cin>>n;for(i=1;i<=n;i++){while(cin>>m&&m)map[i][m]=1;}tarjan();sovle();if(res==1) cout<<"0"<<endl;else cout<<ans<<endl;}return 0;}


0 0
原创粉丝点击