题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=424&page=show_problem&problem=3187
题目大意:共有n个人,n<=25,如果两个人互相打电话(直接或间接),则称他们在同一个电话圈中,如a打给b,b打给c,c打给d,d打给a,则这四个人在同一个圈里;如a给b打,b不给a打(直接或间接),则a、b不在同一个圈中。给出m条通话情况,求出各个电话圈中的所有人。
分析:显然可以构造一个有向图,若两点互相有通路,则在同一个电话圈中,可以用Floyd先求出任意两点是否能互相到达,再输出各个分量的名字。在这里输出时用dfs把每个强连通分量遍历输出。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<map> 6 using namespace std; 7 const int Maxn=30; 8 int n,m,d[Maxn][Maxn],kase=0,have[Maxn]; 9 string num[Maxn]; 10 //vector<int> G[Maxn]; 11 map<string,int>name; 12 void read(){ 13 int count=0; 14 memset(d,0,sizeof(d)); 15 for(int i=0;i<m;i++){ 16 string s1,s2; 17 cin>>s1>>s2; 18 if(!name.count(s1)){name[s1]=count;num[count++]=s1;} 19 if(!name.count(s2)){name[s2]=count;num[count++]=s2;} 20 d[name[s1]][name[s2]]=1; 21 } 22 } 23 void Floyd(){ 24 for(int k=0;k<n;k++){ 25 for(int i=0;i<n;i++){ 26 for(int j=0;j<n;j++){ 27 d[i][j]=d[i][j]||(d[i][k]&&d[k][j]); 28 } 29 } 30 } 31 } 32 bool dfs(int s,bool first){ 33 if(have[s])return false; 34 if(!first)cout<<", "; 35 cout<<num[s]; 36 have[s]=1; 37 for(int i=0;i<n;i++){ 38 if(s==i)continue; 39 if(d[s][i]&&d[i][s]&&!have[i]){ 40 dfs(i,false); 41 } 42 } 43 return true; 44 } 45 int main(){ 46 while(cin>>n>>m&&n&&m){ 47 name.clear(); 48 if(kase)cout<<endl; 49 cout<<"Calling circles for data set "<<++kase<<':'<<endl; 50 read(); 51 Floyd(); 52 memset(have,0,sizeof(have)); 53 for(int i=0;i<n;i++){ 54 if(dfs(i,true))cout<<endl; 55 } 56 } 57 return 0; 58 }