标签:
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\n",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("\n"); 144 } 145 }
标签:
原文地址:http://www.cnblogs.com/yuemo/p/5494562.html