tarjan——cogs 1298 通讯问题

1298. 通讯问题

★   输入文件:jdltt.in   输出文件:jdltt.out   简单对比
时间限制:1 s   内存限制:128 MB

【题目描述】

一个篮球队有n个篮球队员,每个队员都有联系方式(如电话、电子邮件等)。但并不是每个队员的联系方式都公开,每个队员的联系方式只有一部分队员知道。问队员可以分成多少个小组,小组成员之间可以相互通知(包括一个队员一个组,表示自己通知自己)。

【输入格式】

 

输入文件有若干行

第一行,一个整数n,表示共有n个队员(2<=n<=100)

下面有若干行,每行2个数a、b,a、b是队员编号,表示a知道b的通讯方式。

 

【输出格式】

 

输出文件有若干行

第一行,1个整数m,表示可以分m个小组,下面有m行,每行有若干个整数,表示该小组成员编号,输出顺序按编号由小到大。

 

【样例输入】

12
1 3
2 1
2 4
3 2
3 4
3 5
4 6 
5 4
6 4
7 4
7 8
7 12
8 7
8 9
10 9
11 10

 

【样例输出】

 

 

8

1 2 3

4 6

5

7 8

9

10

11

12

 

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<vector>
  5 #include<algorithm>
  6 
  7 #define M 200
  8 
  9 using namespace std;             
 10 
 11 int pp[M];
 12 int tk[M],top=0;          
 13 bool stk[M];            //标记点是否已在队列中 
 14 int dfn[M];             //记录点的标号 
 15 int low[M];             //记录点的最小上溯点位 
 16 int cnum=0;             //统计强连通分量个数 
 17 int dex=0;              //入队编号 
 18 vector <int> edge[M];   //储存边 
 19 int com[M][M];         //储存强连通分量(原来用的是动态数组,但是忘了动态数组怎么排序了……所以换成了二维数组) 
 20 int n;
 21 
 22 void input();
 23 void output();
 24 void tarjan(int);
 25 void chushihua();
 26 void jiaohuan(int,int);
 27 
 28 int main()
 29   {
 30       freopen("jdltt.in","r",stdin);
 31       freopen("jdltt.out","w",stdout);
 32       input();
 33       chushihua();
 34       output();
 35       fclose(stdin);fclose(stdout);
 36       return 0;
 37   }
 38 
 39 void input()
 40   {
 41       
 42       scanf("%d",&n);
 43       int a,b;
 44       while(scanf("%d%d",&a,&b)==2)
 45         {
 46             edge[a].push_back(b);
 47         }
 48   }
 49 
 50 void chushihua()                 //各种初始化…… 
 51   { 
 52       memset(tk,-1,sizeof(tk));
 53       memset(stk,0,sizeof(stk));
 54       memset(dfn,-1,sizeof(dfn));
 55       memset(low,-1,sizeof(low));
 56       for(int i=1;i<=n;i++)        //如果对该点还没入队过就跑一次tarjan 
 57         if(dfn[i]==-1)
 58           tarjan(i);
 59   }
 60 
 61 void tarjan(int i)
 62   {
 63       int j;
 64       dfn[i]=low[i]=dex++;         
 65       stk[i]=true;                 //入队标记 
 66       tk[++top]=i;                 //入队
 67       for(int e=0;e<edge[i].size();e++)       //遍历所有与该点相连的点 
 68         {
 69             j=edge[i][e];                      
 70             if(dfn[j]==-1)                      //情况一:点未入队——入队跑tarjan 
 71               {
 72                   tarjan(j);
 73                   low[i]=min(low[i],low[j]);
 74               }
 75         else
 76           if(stk[j]==1)                     //情况二:已入过对且正在队中 
 77             low[i]=min(low[i],dfn[j]);
 78         }
 79     if(dfn[i]==low[i])                      //强连通分量标识 
 80       {
 81           cnum++;
 82           do
 83             {
 84                 j=tk[top--];
 85 //                printf("%d ",j);
 86                 stk[j]=false;
 87                 com[cnum][0]++;
 88                 com[cnum][com[cnum][0]]=j;
 89             }
 90         while(j!=i);
 91       }
 92   }
 93 /*
 94 void jiaohuan(int a,int b)
 95   {
 96       memset(pp,0,sizeof(pp));
 97     int i=0;
 98     while(cc[a][i]!=0)
 99       {pp[i]=cc[a][i];i++;}
100     memset(cc[a],0,sizeof(cc[a]));
101     i=0;
102     while(cc[b][i]!=0)
103       cc[a][i]=cc[b][i],i++;
104     memset(cc[b],0,sizeof(cc[b]));
105     i=0;
106     while(pp[i]!=0)
107       cc[b][i]=pp[i],i++;
108   }
109 */
110 
111 void output()
112   {
113       printf("%d
",cnum);
114       for(int k=1;k<=cnum;k++)            //先把每个强连通分量里的点按从小到大排序
115                                         //(有智商的孩子就不要像我一样用冒泡排序了……) 
116         {
117             int p=com[k][0];
118             for(int i=1;i<=p;i++)
119               for(int j=i+1;j<=p;j++)
120                 if(com[k][i]>com[k][j])
121                   {
122                       int b=com[k][i];
123                       com[k][i]=com[k][j];
124                       com[k][j]=b;
125                   }
126         }
127     for(int i=1;i<=cnum;i++)           //把强连通分量按首的大小从小到大排序,依旧是冒泡…… 
128       for(int j=i+1;j<=cnum;j++)
129         if(com[i][1]>com[j][1])        //我的com[i][0]储存的是第i个强连通分量包含几个点 
130           {
131               memset(pp,0,sizeof(pp));
132               for(int k=0;k<=com[i][0];k++)
133                 pp[k]=com[i][k];
134               for(int k=0;k<=com[j][0];k++)
135                 com[i][k]=com[j][k];
136               for(int k=0;k<=pp[0];k++)
137                 com[j][k]=pp[k];
138           }
139       for(int i=1;i<=cnum;i++)          //真正的输出过程…… 
140         {
141             for(int j=1;j<=com[i][0];j++)
142               printf("%d ",com[i][j]);
143             printf("
");
144         }
145   }
tarjan
原文地址:https://www.cnblogs.com/yuemo/p/5494562.html