博客 UVA 247 calling circles floyd-warshall算法

题目大意描述,给出一条通话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
#include
#include
#include
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");
	}
}


你可能感兴趣的:(图论,图论,uva,247)