uva_247_Calling Circles(floyd传递闭包)

Calling Circles

Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu

Submit
Status

Description

If you‘ve seen television commercials for long-distance phone companies lately, you‘ve noticed that many companies have been spending a lot of money trying to convince people that they provide the best service at the lowest cost.
One company has calling circles." You provide a list of people that you call most frequently. If you call someone in your calling circle (who is also a customer of the same company), you get bigger discounts than if you call outside your circle. Another company
points out that you only get the big discounts for people in your calling circle, and if you change who you call most frequently, it‘s up to you to add them to your calling circle.

LibertyBell Phone Co. is a new company that thinks they have the calling plan that can put other companies out of business. LibertyBell has calling circles, but they gure out your calling circle for you. This is how it works.
LibertyBell keeps track of all phone calls. In addition to yourself, your calling circle consists of all people whom you call and who call you, either directly or indirectly.For example, if Ben calls Alexander, Alexander calls Dolly, and Dolly calls Ben, they
are all within the same circle. If Dolly also calls Benedict and Benedict calls Dolly, then Benedict is in the same calling circle as Dolly, Ben, and Alexander. Finally, if Alexander calls Aaron but Aaron doesn‘t call Alexander, Ben, Dolly, or Benedict, then
Aaron is not in the circle.You‘ve been hired by LibertyBell to write the program to determine calling circles given a log of phone calls between people.

Input

The  input  file  will  contain  one  or  more  data  sets.   Each  data  set  begins  with  a  line  containing  two integers,n and m.The first integer,n, represents the number of different people who are in the data set.  The maximum value for

n is 25.  The remainder of the data set consists of m lines, each representing a phone call.  Each call is represented by two names, separated by a single space.  Names are rst names only (unique within a data set), are case sensitive, and consist of only alphabetic
characters; no name is longer than 25 letters.

For example, if Ben called Dolly, it would be represented in the data file as

Ben Dolly

Input is terminated by values of zero (0) for n and m.

Output

For each input set,  print a header line with the data set number,  followed by a line for each calling circle in that data set.  Each calling circle line contains the names of all the people in any order within the circle, separated by comma-space (a comma
followed by a space).  Output sets are separated by blank lines.

Sample Input

5 6

Ben Alexander

Alexander Dolly

Dolly Ben

Dolly Benedict

Benedict Dolly

Alexander Aaron

14 34

John Aaron

Aaron Benedict

Betsy John

Betsy Ringo

Ringo Dolly

Benedict Paul

John Betsy

John Aaron

Benedict George

Dolly Ringo

Paul Martha

George Ben

Alexander George

Betsy Ringo

Alexander Stephen

Martha Stephen

Benedict Alexander

Stephen Paul

Betsy Ringo

Quincy Martha

Ben Patrick

Betsy Ringo

Patrick Stephen

Paul Alexander

Patrick Ben

Stephen Quincy

Ringo Betsy

Betsy Benedict

Betsy Benedict

Betsy Benedict

Betsy Benedict

Betsy Benedict

Betsy Benedict

Quincy Martha

0 0

Sample Output

Calling circles for data set 1:

Ben, Alexander, Dolly, Benedict

Aaron

Calling circles for data set 2:

John, Betsy, Ringo, Dolly

Aaron

Benedict

Paul, George, Martha, Ben, Alexander, Stephen, Quincy, Patrick

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

分析:本题一看就是求有向图的强连通分量问题。可以用tarjan解决。但是注意到数据比较小,还可以想到另外一个算法——floyd。在有向图中,有时不必关心路径的长度,只关心每两点之间是否有通路,则可以用1和0表示“连通”和“不连通”。这样,就可以用floyd解决了:dp[i][j]=dp[i][j]||(dp[i][k]&&dp[k][j])。这样的结果称为有向图的传递闭包(Transitive Closure)。

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20840

代码清单:

floyd算法

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<cctype>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxs = 25 + 5;
const int maxn = 2000 + 5;
const int maxv = 4000000 + 5;

int n,m,cases=0;
int dp[maxs][maxs];
int idx1,idx2,cnt;
string name1,name2;
string rstr[maxs];
map<string,int>idx;
bool vis[maxs];

void init(){
    cnt=0; idx.clear();
    memset(dp,0,sizeof(dp));
    memset(vis,false,sizeof(vis));
}

int get_idx(string name){
    if(idx.count(name)) return idx[name];
    idx[name]=++cnt; rstr[cnt]=name;
    return cnt;
}

void input(){
    for(int i=1;i<=m;i++){
        cin>>name1>>name2;
        idx1=get_idx(name1);
        idx2=get_idx(name2);
        dp[idx1][idx2]=1;
    }
}

void floyd(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                dp[i][j]=dp[i][j]||(dp[i][k]&&dp[k][j]);
        }
    }
}

void solve(){
    floyd();
    if(cases) cout<<endl;
    printf("Calling circles for data set %d:\n",++cases);
    for(int i=1;i<=n;i++){
        if(vis[i]) continue;
        cout<<rstr[i];
        for(int j=i+1;j<=n;j++){
            if(vis[j]) continue;
            if(dp[i][j]&&dp[j][i]){
                vis[j]=true;
                cout << ", " <<rstr[j];
            }
        }cout<<endl;
    }
}

int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0&&m==0) break;
        init();
        input();
        solve();
    }return 0;
}

tarjan算法

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<stack>
#include<ctime>
#include<cctype>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;

const int maxs = 25 + 5;

int n,m,cases=0;
int idx1,idx2,cnt;
string name1,name2;
string rstr[maxs];
map<string,int>idx;

int sccno,no;
int dfn[maxs];
int low[maxs];
bool InStack[maxs];
stack<int>sta;
vector<int>graph[maxs];

void init(){
    cnt=no=0;
    idx.clear();
    for(int i=1;i<=maxs;i++){
        dfn[i]=low[i]=0;
        InStack[i]=false;
        graph[i].clear();
    }
    while(!sta.empty()) sta.pop();
}

int get_idx(string name){
    if(idx.count(name)) return idx[name];
    idx[name]=++cnt; rstr[cnt]=name;
    return cnt;
}

void input(){
    for(int i=1;i<=m;i++){
        cin>>name1>>name2;
        idx1=get_idx(name1);
        idx2=get_idx(name2);
        graph[idx1].push_back(idx2);
    }
}

void tarjan(int u){
    low[u]=dfn[u]=++no;
    InStack[u]=true; sta.push(u);
    for(int i=0;i<graph[u].size();i++){
        int v=graph[u][i];
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(InStack[v]){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]){
        int vv=-1;
        while(!sta.empty()&&vv!=u){
            vv=sta.top();
            sta.pop();
            InStack[vv]=false;
            if(vv==u) cout<<rstr[vv]<<endl;
            else cout<<rstr[vv]<<", ";
        }
    }
}

void solve(){
    if(cases) cout<<endl;
    printf("Calling circles for data set %d:\n",++cases);
    for(int i=1;i<=n;i++){
        if(!dfn[i]) tarjan(i);
    }
}

int main(){
    while(scanf("%d%d",&n,&m)!=EOF){
        if(!n&&!m) break;
        init();
        input();
        solve();
    }return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-16 12:41:49

uva_247_Calling Circles(floyd传递闭包)的相关文章

UVA 247 电话圈 (floyd传递闭包 + dfs输出连通分量)

题意:输出所有的环: 思路:数据比较小,用三层循环的floyd传递闭包(即两条路通为1,不通为0,如果在一个环中,环中的所有点能互相连通),输出路径用dfs,递归还没有出现过的点(vis),输出并递归该点与其他点能互达的点: 1 #include <cstdio> 2 #include <vector> 3 #include <string> 4 #include <cstring> 5 #include <iostream> 6 using n

hdu 1704 Rank(floyd传递闭包)

题目链接:hdu 1704 Rank 题意: 有n个人,m场比赛,a与b打,每场都是awin,问不能确定其中两个人的win情况数. 题解: floyd传递闭包,这里我用bitset优化了一下. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 bitset<501>a[501]; 5 6 int n,m,t; 7 8 int main(){ 9

POJ 2594 —— Treasure Exploration——————【最小路径覆盖、可重点、floyd传递闭包】

Treasure Exploration Time Limit:6000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2594 Description Have you ever read any book about treasure exploration? Have you ever see any film about treasure exploratio

POJ3660:Cow Contest(Floyd传递闭包)

Cow Contest Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 16941   Accepted: 9447 题目链接:http://poj.org/problem?id=3660 Description: N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating in a programming contest. As we all k

UVa 247 电话圈(Floyd传递闭包)

https://vjudge.net/problem/UVA-247 题意: 如果两个人相互打电话,则说他们在同一个电话圈里.例如,a打给b,b打给c,c打给d,d打给a,则这4个人在同一个圈里:如果e打给f但f不打给e,则不能推出e和f在同一个电话圈里,输出所有电话圈. 思路: 通过Floyd求一个传递闭包.最后dfs输出每一个电话圈即可. 传递闭包的求法: 1 for (int k = 0; k < n;k++) 2 for (int i = 0; i < n;i++) 3 for (in

UVa247 Calling Circles (Floyd,DFS)

链接:http://bak3.vjudge.net/problem/UVA-247 分析:先用Floyd求出有向图的传递闭包,然后用DFS求出各个联通分量即可. 1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <string> 5 using namespace std; 6 7 vector<string> names; 8 int ID(const

POJ 1094 Sorting It All Out【floyd传递闭包+拓扑排序】

Sorting It All Out Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 31994 Accepted: 11117 Description An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from small

【日常学习】【floyd传递闭包+高精】codevs1009 产生数题解

题目描述 Description 给出一个整数 n(n<10^30) 和 k 个变换规则(k<=15). 规则: 一位数可变换成另一个一位数: 规则的右部不能为零. 例如:n=234.有规则(k=2): 2-> 5 3-> 6 上面的整数 234 经过变换后可能产生出的整数为(包括原数): 234 534 264 564 共 4 种不同的产生数 问题: 给出一个整数 n 和 k 个规则. 求出: 经过任意次的变换(0次或多次),能产生出多少个不同整数. 仅要求输出个数. 输入描述 

UVa 247 Calling Circles【传递闭包】

题意:给出n个人的m次电话,问最后构成多少个环,找出所有的环 自己想的是:用map来储存人名,每个人名映射成一个数字编号,再用并查集,求出有多少块连通块,输出 可是map不熟,写不出来,而且用并查集输出的时候感觉貌似很麻烦 然后再用的传递闭包,可是判断到d[i][j]==1和d[j][i]==1,该怎么输出路径呢 于是看了lrj的代码= = 用的是一个ID(string s)函数来给名字编号,和第五章的集合栈计算机那题的办法一样 然后用dfs输出路径= =(这个要好好--好好--好好学) 最后还