UVA247[Calling Circles] Floyed求传递闭包 || tarjan求SCC

来源:互联网 发布:质量好的挎包淘宝店 编辑:程序博客网 时间:2024/06/07 20:08

题目链接


题意:如果两个人互相打电话(直接或者间接),则说他们在同一个电话圈里。例如,a打给b,b打给c,c打给d,d打给a,则这四个人在同一个圈里;如果e打给f,而f不打给e,则不能推出e和f在同一个电话圈。输入n(n<=25)个人的m次电话,找出所有的电话圈。人名只包含字母,不超过25个字符,且不重复。


solution_1:tarjan求有向图SCC

#include <map>#include <stack> #include <cstdio>#include <vector>#include <cstring>#include <iostream>using namespace std;const int N = 50;vector<int> G[N];stack<int> S;int dfn[N], low[N];bool bl[N];int id;map<string,int> mp1;map<int,string> mp2;int tot=0;int Hash(string str){    if( mp1.count(str) ) return mp1[str];    mp1[str]=++tot;    mp2[tot]=str;    return tot;} void dfs(int u){    dfn[u]=low[u]=++id;    S.push(u);    bl[u]=true;    for ( int i=0; i<G[u].size(); i++ ){        int v=G[u][i];        if( !dfn[v] ) {            dfs(v);            low[u]=min(low[u],low[v]);        } else if( bl[v] ){            low[u]=min(low[u],dfn[v]);        }    }    if( low[u]==dfn[u] ){        int ok=0;        while( !S.empty()){            int x=S.top(); S.pop();            bl[x]=false;            if( !ok ) cout<<mp2[x], ok=1;            else cout<<", "<<mp2[x];            if( x==u ) {                break;            }        }        cout<<"\n";    }}void find_scc(int n){    memset(dfn,0,sizeof(dfn));    memset(low,0,sizeof(low));    memset(bl,0,sizeof(bl));    id=0;    for ( int i=1; i<=n; i++ )        if( !dfn[i] ) dfs(i); }int n, m;int main(){    int k=0;    while( ~scanf("%d%d", &n, &m ) && (n||m) ){        if( k ) cout<<"\n";        printf("Calling circles for data set %d:\n", ++k);          for ( int i=0; i<N; i++ ) G[i].clear();        tot=0;        mp1.clear(); mp2.clear();        for ( int i=1; i<=m; i++ ){            string s1,s2;            cin>>s1>>s2;            int x=Hash(s1), y=Hash(s2);            G[x].push_back(y);          }        find_scc(n);    }}

solution_2: Floyed求传递闭包

#include <map>#include <stack> #include <cstdio>#include <vector>#include <cstring>#include <iostream>using namespace std;const int N = 30;int a[N][N];bool vis[N];map<string,int> mp1;map<int,string> mp2;int tot=0;int Hash(string str){    if( mp1.count(str) ) return mp1[str];    mp1[str]=++tot;    mp2[tot]=str;    return tot;} int n, m;int main(){    int k=0;    while( ~scanf("%d%d", &n, &m ) && (n||m) ){        if( k ) cout<<"\n";        printf("Calling circles for data set %d:\n", ++k);          memset(a,0,sizeof(a));        memset(vis,0,sizeof(vis));        tot=0;        mp1.clear(); mp2.clear();        for ( int i=1; i<=m; i++ ){            string s1,s2;            cin>>s1>>s2;            int x=Hash(s1), y=Hash(s2);            a[x][y]=1;        }        for ( int k=1; k<=n; k++ )            for ( int i=1; i<=n; i++ )                for ( int j=1; j<=n; j++ )                    a[i][j]=a[i][j] || (a[i][k]&&a[k][j]);        for ( int i=1; i<=n; i++ ){            if( vis[i] ) continue;            vis[i]=1;            cout<<mp2[i];            for ( int j=1; j<=n; j++ )                 if( !vis[j] && a[i][j] && a[j][i] ) {                    vis[j]=1;                    cout<<", "<<mp2[j];                }            cout<<"\n";        }    }}