UVa247 - Calling Circles ( floyed求传递闭包 )
题意
电话圈, 每行输出在一个圈内的人名
思路
有向图的传递闭包
该有向图中, 并不需要关心路径长度, 只需要关心两点之间是否有通路, 则可以用”1”和”0”表示”连通”和”不连通”. 这样只需要将floyed算法中的语句改为 d[i][j] = d[i][j]||(d[i][k]&&d[k][j])
即可求得传递闭包
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <set>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
int n, m;
map<int, string> ID;
set<string> names;
const int maxn = 30;
int g[maxn][maxn];
int f[maxn];
vector<string> vec[maxn];
void init()
{
if(!names.empty()) names.clear();
if(!ID.empty()) ID.clear();
for( int i = 0; i <= n; i++ )
vec[i].clear();
memset(g, 0, sizeof g);
for(int i = 1; i <= n; i++)
f[i] = i;
}
int find_(int a)
{
if( f[a] != a ) f[a] = find_(f[a]);
return f[a];
}
void union_(int a, int b)
{
int aa = find_(a), bb = find_(b);
if(aa!=bb)
{
f[bb] = aa;
}
return;
}
void floyed(){ // floyed 求传递闭包
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]);
}
int findid(string a){
map<int, string>::iterator it = ID.begin();
for(;it!=ID.end();it++){
if( it->second == a )
return it->first;
}
}
int main()
{
string stra, strb;
int cnt;
int num = 0;
while( cin >> n >> m && n && m ){
cnt = 0;
init();
for(int i = 0; i < m; i++){
cin >> stra >> strb;
if(!names.count(stra)){ ID[++cnt] = stra; names.insert(stra); }
if(!names.count(strb)){ ID[++cnt] = strb; names.insert(strb); }
g[findid(stra)][findid(strb)] = 1;
}
floyed();
printf("Calling circles for data set %d:\n", ++num);
for(int i = 1 ; i <= n; i++ ){
for(int j = i+1; j <= n; j++){
if( g[i][j] == 1 && g[j][i] == 1 ){
union_(i, j);
}
}
}
for(int i = 1; i <= n; i++)
{
vec[f[i]].push_back(ID[i]);
}
for(int i = 1; i <= n; i++){
if( vec[i].size() == 0 ) continue;
for(int j = 0; j < (int)vec[i].size(); j++){
if( j != 0 ) cout << ", ";
cout << vec[i][j];
}
cout << "\n";
}
}
return 0;
}