poj 1236
题目大意:网络中的一学校可以将软件发送给其他一些学校,能够发送给谁取决于他们各自维护的一个清单。将学校看成一个节点,给出每个学校的维护清单,问至少需要复制几次软件,使毎个学校都能够得到该软件,在清单中至少添加几项,可使软件至少复制一次,所有学校都可以得到。
思路:
1、用Tarjan算法求出强连通分分量。2、缩点重新构图。3、分别求节点的出度和入度。
第一个问题就是出度的个数,第二问题就是出度和入度中的较大者。
代码如下:
#include<iostream> #include<cstring> #include<vector> #include<stack> using namespace std; vector <int> map[101]; stack <int> S; int low[101],pre[101],post[101],indegree[101],outdegree[101],ss[101],cnt,time,in,out; int tarjan(int s) { int i,k,e; pre[s]=cnt++;low[s]=pre[s]; post[s]=1;S.push(s); for(i=0;i<map[s].size();i++) { k=map[s][i]; if(!pre[k]) { tarjan(k); low[s]=(low[s]<low[k]) ? low[s]:low[k]; } else if(post[k] && low[s]>pre[k]) { low[s]=pre[k]; } } if(pre[s]==low[s]) { time++; for(e=S.top(),S.pop();e!=s;e=S.top(),S.pop()) { ss[e]=time; post[e]=0; } ss[e]=time; post[e]=0; } return 0; } int solve(int n) { int i,j,k; if(time==1) { in=1; return 0; } memset(indegree,0,sizeof(indegree)); memset(outdegree,0,sizeof(outdegree)); for(i=1;i<=n;i++) for(j=0;j<map[i].size();j++) { k=map[i][j]; if(ss[i]!=ss[k]) { indegree[ss[k]]++; outdegree[ss[i]]++; } } for(out=in=0,i=1;i<=time;i++) { if(indegree[i]==0) in++; if(outdegree[i]==0) out++; } return in>out? in:out; } int main() { int i,m,n,k; while(cin>>n) { for(i=1;i<=n;i++) while(cin>>m && m) if(m!=i) map[i].push_back(m); memset(low,0,sizeof(low)); memset(pre,0,sizeof(pre)); memset(post,0,sizeof(post)); memset(ss,0,sizeof(ss)); for(cnt=1,time=0,i=1;i<=n;i++) if(!pre[i]) tarjan(i); k=solve(n); cout<<in<<endl<<k<<endl; for(i=0;i<=n;i++) map[i].clear(); } return 0; }