若是兩我的互相打電話(直接或者間接),則說他們在同一個電話圈裏。例如,\(a\)打給\(b\),\(b\)打給\(c\),\(c\)打給\(d\),\(d\)打給\(a\),則這四我的在同一個圈裏;若是\(e\)打給\(f\),而\(f\)不打給\(e\),則不能推出\(e\)和\(f\)在同一個電話圈。輸入\(n(n≤25)\)我的的\(m\)次電話,找出全部的電話圈。人名只包含字母,不超過\(25\)個字符,且不重複。c++
\(Floyd\text{傳遞閉包}\)算法
首先用\(Floyd\)求出傳遞閉包,即g[i][j]
表示i
是否直接或間接向j
打過電話,當且僅當g[i][j]=g[j][i]=1
時兩者處於同一個電話圈。構造一個新圖,在「一個電話圈裏」的兩我的之間連一條邊,而後依次輸出各個聯通份量的全部人便可。閉包
#include<bits/stdc++.h> using namespace std; map<string,int>mp; string st[30]; string st1,st2; bool g[30][30]; bool used[30]; int sum; int n,m; int T; int main() { cin>>n>>m; while(1) { sum=0; T++; //cout<<T<<endl; memset(g,0,sizeof(g)); memset(used,0,sizeof(used)); mp.clear(); for(int i=1;i<=m;i++) { cin>>st1>>st2; if(!mp[st1]) { mp[st1]=++sum; st[sum]=st1; } if(!mp[st2]) { mp[st2]=++sum; st[sum]=st2; } g[mp[st1]][mp[st2]]=1; } for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { g[i][j]=g[i][j] || (g[i][k] && g[k][j]); } } } printf("Calling circles for data set %d:\n",T); /*for(int i=1;i<=n;i++) cout<<st[i]<<" ";cout<<endl;*/ for(int i=1;i<=n;i++) { if(!used[i]) { cout<<st[i]; used[i]=1; for(int j=1;j<=n;j++) { if(g[i][j]&&g[j][i]&&!used[j]) { cout<<", "<<st[j]; used[j]=1; } } cout<<endl; } } cin>>n>>m; if(n||m)cout<<endl; else break; } return 0; }
劉汝佳大法好!spa