Calling Circles UVA - 247 (有向图的传递凸包)

传送门

题意:如果两个人相互打电话(直接或者间接),则说他们在同一个电话圈中,输入n个人的m次电话,找出所有的电话圈。

题解:首先用floyd求出传递凸包,当且仅当d[i][j]=d[j][i]=1时二者处于同一个电话圈,构造一个新图,在一个电话圈里的两个人之间连一条边,然后依次输出各个连通分量的所有人即可。

附上代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn=30;
const int maxm=1e3+50;

int n,m;
int d[maxn][maxn];

vector<string>name;

int trans(string temp)
{
    int ssize=name.size();
    for(int i=0;i<ssize;i++){
        if(temp==name[i]){
            return i;
        }
    }
    name.push_back(temp);
    return ssize;
}

bool done[maxn];

void dfs(int u)
{
    done[u]=1;
    for(int v=0;v<n;v++){
        if(!done[v]&&d[u][v]&&d[v][u]){
            cout<<", "<<name[v];
            dfs(v);
        }
    }
}

int main()
{
    int casen=1;
    while(cin>>n>>m){
        if(n==0&&m==0){
            break;
        }else{
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    if(i==j){
                        d[i][j]=1;
                    }else{
                        d[i][j]=0;
                    }
                }
            }
            name.clear();
            string temp1,temp2;
            for(int i=0;i<m;i++){
                cin>>temp1>>temp2;
                d[trans(temp1)][trans(temp2)]=1;
            }
            for(int k=0;k<n;k++){
                for(int i=0;i<n;i++){
                    for(int j=0;j<n;j++){
                        d[i][j]=d[i][j]||(d[i][k]&&d[k][j]);
                    }
                }
            }
            if(casen>1){
                printf("\n");
            }
            memset(done,false,sizeof(done));
            cout<<"Calling circles for data set "<<casen++<<":"<<endl;
            for(int i=0;i<n;i++){
                if(!done[i]){
                    cout<<name[i];
                    dfs(i);
                    cout<<endl;
                }
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值