A - Network of Schools POJ - 1236

A - Network of Schools

 POJ - 1236 

1、问题要求至少需要几个文件,也就是求入度为0的强连通分量的数量。

求需要把图连通起来再加几条边?

因为对于某单个强联通分支,如果入度为0或出度为0那一定需要加边才可以和其他的强连通,因此可以统计入度为0和和出度为0的强连通分支数目。那答案就是  ans=maxd-d+);

2强联通分量的tarjan算法

几个需要注意的点。

(1)建图使用链式前向星方式

head[i]记录点i 第一条边在边集中的位置

e[j].next记录i的下一条边的位置

初始化令head[i]=-1

adde 是加边函数

struct edge{
    int v,nexte;
}e[MAXN*MAXN];

void adde(int u,int v)
{
    e[k].v=v;
    e[k].nexte=head[u];
    head[u]=k++;
}

(2)tarjan模板

 1 void tarjan(int u)
 2 {
 3     int v;
 4     dfn[u]=low[u]=++idx;
 5     vis[u]++;
 6     S.push(u);
 7     
 8     for(int i=head[u];i!=-1;i=e[i].nexte)
 9     {
10         v=e[i].v;
11         if(!dfn[v])
12         {
13             tarjan(v);
14             low[u]=min(low[u],low[v]);
15         }
16         else if(vis[v])
17             low[u]=min(low[u],low[v]);
18     }
19     if(dfn[u]==low[u])
20     {
21         Bcnt++;
22         do{
23             v=S.top();
24             S.pop();
25             vis[v]=0;
26             belong[v]=Bcnt;
27         }
28         while(u!=v);
29     }
30     
31 }

belong数组记录了连通分量点i属于的连通分量。

(3)计算入度和出度

 1     for(int i=1;i<=n;i++)
 2     {
 3         for(int j=head[i];j!=-1;j=e[j].nexte)
 4         {
 5             int v=e[j].v;
 6             if(belong[i]!=belong[v])
 7             {
 8                 cd[belong[i]]++;
 9                 rd[belong[v]]++;
10             }
11         }
12     }//通过遍历的方式计算出每个连通分量的入度和出度 

AC代码:

  1 #include <iostream>
  2 #include <cstring>
  3 #include <string>
  4 #include <map>
  5 #include <set>
  6 #include <algorithm>
  7 #include <fstream>
  8 #include <cstdio>
  9 #include <cmath>
 10 #include <stack>
 11 #include <queue>
 12 using namespace std;
 13 const double Pi=3.14159265358979323846;
 14 typedef long long ll;
 15 const int MAXN=100+5;
 16 const int dx[5]={0,0,0,1,-1};
 17 const int dy[5]={1,-1,0,0,0};
 18 const int INF = 0x3f3f3f3f;
 19 const int NINF = 0xc0c0c0c0;
 20 const ll mod=1e9+7;
 21 int n,head[MAXN];int k=1,idx=0,Bcnt=0;;
 22 int rd[MAXN];
 23 int cd[MAXN];
 24 int belong[MAXN],vis[MAXN],dfn[MAXN],low[MAXN];
 25 set <int> M;
 26 struct edge{
 27     int v,nexte;
 28 }e[MAXN*MAXN];
 29 
 30 void adde(int u,int v)
 31 {
 32     e[k].v=v;
 33     e[k].nexte=head[u];
 34     head[u]=k++;
 35 }
 36 stack <int > S;
 37 void read()
 38 {
 39     cin>>n;
 40     memset(head,-1,sizeof(head));
 41     for(int i=1;i<=n;i++)
 42     {
 43         int b;
 44         while(scanf("%d",&b))
 45         {
 46             if(b==0) break;
 47             adde(i,b);
 48         }
 49     }
 50 }
 51 
 52 void tarjan(int u)
 53 {
 54     int v;
 55     dfn[u]=low[u]=++idx;
 56     vis[u]++;
 57     S.push(u);
 58     
 59     for(int i=head[u];i!=-1;i=e[i].nexte)
 60     {
 61         v=e[i].v;
 62         if(!dfn[v])
 63         {
 64             tarjan(v);
 65             low[u]=min(low[u],low[v]);
 66         }
 67         else if(vis[v])
 68             low[u]=min(low[u],low[v]);
 69     }
 70     if(dfn[u]==low[u])
 71     {
 72         Bcnt++;
 73         do{
 74             v=S.top();
 75             S.pop();
 76             vis[v]=0;
 77             belong[v]=Bcnt;
 78         }
 79         while(u!=v);
 80     }
 81     
 82 }
 83 int main()
 84 {
 85     read();
 86     for(int i=1;i<=n;i++)
 87         if(!dfn[i]) tarjan(i);
 88     for(int i=1;i<=n;i++)
 89     {
 90         for(int j=head[i];j!=-1;j=e[j].nexte)
 91         {
 92             int v=e[j].v;
 93             if(belong[i]!=belong[v])
 94             {
 95                 cd[belong[i]]++;
 96                 rd[belong[v]]++;
 97             }
 98         }
 99     }//通过遍历的方式计算出每个连通分量的入度和出度 
100     int ansc=0,ansr=0;
101     for(int i=1;i<=Bcnt;i++)
102         if(cd[i]==0) ansc++;
103     for(int i=1;i<=Bcnt;i++)    
104         if(rd[i]==0) ansr++;
105     if(Bcnt==1) cout << 1 <<endl<<0<<endl;
106     else cout << ansr <<endl<<max(ansr,ansc)<<endl; 
107     return 0;
108 }

猜你喜欢

转载自www.cnblogs.com/Msmw/p/11142600.html
今日推荐