题意:有N个人互相打了M次电话,请找出所有电话圈(Eg.a→b,b→c,c→d,d→a 就算一个电话圈)并输出。(N≤25,L≤25,注意输出格式)
解法:由于N比较小所有n^2或n^3的复杂度都没有问题。所以就O(n^2)读入;O(n^3)Floyd算法求出传递闭包,d[i][j]表示 i 是否直接或间接给 j 打过电话,并查集并起一个电话圈里的人;O(n^2)输出。总的是O(n^3)的时间复杂度。
P.S.我的代码有点长~再补个连通分量和强连通分量的知识:连通分量——强连通图的连通分量为其本身。如果为非连通图,则连通分量为该图的最大连通子图;有向图强连通分量——在有向图G中,如果两个顶点vi,vj间(vi>vj)有一条从vi到vj的有向路径,同时还有一条从vj到vi的有向路径,则称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。有向图的极大强连通子图,称为强连通分量(strongly connected components)。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 using namespace std; 6 7 const int N=27,M=910; 8 int n,m,T=0; 9 int d[N][N],fa[N]; 10 char s[N],ss[N],str[N][N]; 11 12 void input() 13 { 14 int x,y,len=0; 15 memset(d,0,sizeof(d)); 16 for (int i=1;i<=m;i++) 17 { 18 scanf("%s%s",s,ss); 19 x=y=0; 20 for (int j=1;j<=len;j++) 21 { 22 if (!strcmp(s,str[j])) x=j; 23 if (!strcmp(ss,str[j])) y=j; 24 } 25 if (!x) memcpy(str[++len],s,sizeof(s)),x=len; 26 if (!y) memcpy(str[++len],ss,sizeof(ss)),y=len; 27 d[x][y]=1; 28 } 29 } 30 int ffind(int x) 31 { 32 if (fa[x]!=x) fa[x]=ffind(fa[x]); 33 return fa[x]; 34 } 35 void solve() 36 { 37 for (int k=1;k<=n;k++) 38 for (int i=1;i<=n;i++) 39 for (int j=1;j<=n;j++) 40 d[i][j]=d[i][j]|(d[i][k]&d[k][j]); 41 42 for (int i=1;i<=n;i++) fa[i]=i; 43 for (int i=1;i<=n;i++) 44 for (int j=1;j<=n;j++) 45 { 46 if (!d[i][j] || !d[j][i]) continue; 47 int fx=ffind(i),fy=ffind(j); 48 if (fx!=fy) fa[fx]=fy; 49 } 50 if (T) printf(" "); 51 printf("Calling circles for data set %d: ",++T); 52 for (int i=1;i<=n;i++) 53 { 54 if (fa[i]!=i) continue; 55 printf("%s",str[i]); 56 for (int j=1;j<=n;j++) 57 if (fa[j]==i && i!=j) printf(", %s",str[j]); 58 printf(" "); 59 } 60 } 61 int main() 62 { 63 while (1) 64 { 65 scanf("%d%d",&n,&m); 66 if (!n && !m) break; 67 input(); 68 solve(); 69 } 70 return 0; 71 }