题意:有n个人,m条通话记录,如果a能直接或间接和b通话,b也能直接或间接和a通话,则他们在一个电话圈中,给定这样的n,m,求出所有电话圈
思路:将所有能够直接或间接互通电话的两人加一条边,这个连通分量就是一个电话圈.
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#define Min(a,b) a<b?a:b
using namespace std;
vector<string> g;
vector<int> g2[30];
stack<int> ss;
int di[30][30];
int dfn[30],low[30],instack[30],scc[30],Time,cnt;
void tarjin(int u)
{
dfn[u]=low[u]=++Time;
instack[u]=1;
ss.push(u);
for(int i=0;i<g2[u].size();i++)
{
int v=g2[u][i];
if(!dfn[v])
{
tarjin(v);
low[u]= Min(low[u],low[v]);
}
else if(instack[v])
low[u]=Min(low[u],low[v]);
}
if(low[u]==dfn[u])
{
cnt++;
int x;
do
{
x=ss.top();ss.pop();
instack[x]=0;
scc[x]=cnt;
}while(x!=u);
}
}
int main()
{
int n,m,kcase=0,first=1;
string a,b;
while(scanf("%d%d",&n,&m)&&(n+m))
{
int c,d;
memset(di,0,sizeof(di));
Time=cnt=0;
for(int i=0;i<=30;i++)
g2[i].clear();
g.clear();
while(!ss.empty())ss.pop();
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(instack,0,sizeof(instack));
for(int i=0;i<m;i++)
{
cin>>a>>b;
c=d=-1;
for(int j=0;j<g.size();j++)
{
if(a==g[j])c=j;
if(b==g[j])d=j;
}
if(c==-1)
{
g.push_back(a);
c=g.size()-1;
}
if(d==-1)
{
g.push_back(b);
d=g.size()-1;
}
di[c][d]=1;
}
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(i!=j&&di[i][k]&&di[k][j])di[i][j]=1;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(i!=j&&di[i][j]&&di[j][i])
g2[i].push_back(j);
}
}
for(int i=0;i<n;i++)
if(!dfn[i])tarjin(i);
if(!first)
printf("\n");
else
first=0;
printf("Calling circles for data set %d:\n",++kcase);
for(int i=1;i<=cnt;i++)
{
int fir=1;
for(int j=0;j<n;j++)
if(scc[j]==i)
{
if(fir)
{
cout<<g[j];
fir=0;
}
else
cout<<", "<<g[j];
}
printf("\n");
}
}
}