题目大意描述,给出一条通话ben alex,表示本打给alex,及一条有向边。如果从ben可以到alex且alex可以到ben,则表示他们在
一个电话圈内。每一行输出一组在一个电话圈内的人。
基本思路:在图中记录下已经存在的单向边,通过三层循环枚举每个点即它们的中间节点。
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++){
Map[j][k] |= Map[j][i] && Map[i][k];// |=为按位或运算 即00-0 01-1 10-1 11-1
} // 解释起来就是只要jk已经联通 或者 j到i联通且i到k联通 那么j到k就是联通的
完整代码:
#include<iostream>
#include<cstring>
#include<climits>
#include<queue>
using namespace std;
const int X=30;
int Map[X][X];
int vis[X];
struct Name{
char Na[X];
}N[X];
bool NCheck(char temp[X],int sum);
int Find(char temp[X],int sum);
void Floyd_warshall(int n);
void display(int n);
int main(){
int n,m,T=1;
while(scanf("%d%d",&n,&m)!=EOF &&n!=0 &&m!=0){
memset(Map,0,sizeof(Map));
int sum=0;
while(m--){
bool mark=true;
char temp1[X],temp2[X];
scanf("%s%s",&temp1,&temp2);
if(NCheck(temp1,sum)==true){
sum++;
strcpy(N[sum].Na,temp1);
}
if(NCheck(temp2,sum)==true){
sum++;
strcpy(N[sum].Na,temp2);
}
int a=Find(temp1,sum);
int b=Find(temp2,sum);
Map[a][b]=1;
}
for(int i=0;i<=n;i++)Map[i][i]=1;
Floyd_warshall(n);
printf("Calling circles for data set %d:\n",T);
T++;
display(n);
}
return 0;
}
bool NCheck(char temp[X],int sum){
for(int i=1;i<=sum;i++)if(strcmp(N[i].Na,temp)==0)return false;
return true;
}
int Find(char temp[X],int sum){
for(int i=1;i<=sum;i++)if(strcmp(N[i].Na,temp)==0)return i;
}
void Floyd_warshall(int n){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
Map[j][k] |= Map[j][i] && Map[i][k];
}
void display(int n){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++){
if(vis[i]==1)continue;
printf("%s",N[i].Na);
for(int j=i+1;j<=n;j++){
if(vis[j]==1)continue;
if(Map[i][j]&&Map[j][i]){
vis[j]=1;
printf(", %s",N[j].Na);
}
}printf("\n");
}
}