UVa 247 - Calling Circles(Floyd求有向图的传递闭包)

链接:

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=183

题意:

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

分析:

首先用floyd求出传递闭包,即G[i][j]表示i是否直接或者间接给j打过电话。
则当且仅当G[i][j]=G[j][i]=true时二者处于一个电话圈。
依此结论直接判断输出即可。

代码:

 1 import java.io.*;
 2 import java.util.*;
 3 import static java.util.Arrays.*;
 4
 5 public class Main {
 6     Scanner cin = new Scanner(new BufferedInputStream(System.in));
 7     final int UP = 25 + 5;
 8     boolean vis[] = new boolean[UP], G[][] = new boolean[UP][UP];
 9     ArrayList<String> name = new ArrayList<String>();
10
11     int id(String s) {
12         for(int i = 0; i < name.size(); i++) {
13             if(name.get(i).equals(s)) return i;
14         }
15         name.add(s);
16         return name.size() - 1;
17     }
18
19     void MAIN() {
20         for(int cases = 1; ; cases++) {
21             int n = cin.nextInt();
22             int m = cin.nextInt();
23             if(n == 0 && m == 0) break;
24             name.clear();
25             for(int t = 0; t < n; t++)
26                 for(int i = 0; i < n; i++) G[t][i] = false;
27             for(int i = 0; i < m; i++)
28                 G[id(cin.next())][id(cin.next())] = true;
29
30             for(int i = 0; i < n; i++) G[i][i] = true;
31             for(int k = 0; k < n; k++) {
32                 for(int i = 0; i < n; i++) {
33                     for(int j = 0; j < n; j++) G[i][j] |= G[i][k] & G[k][j];
34                 }
35             }
36
37             if(cases > 1) System.out.println();
38             System.out.printf("Calling circles for data set %d:\n", cases);
39             fill(vis, false);
40             for(int t = 0; t < n; t++) {
41                 if(vis[t]) continue;
42                 System.out.printf("%s", name.get(t));
43                 for(int i = t+1; i < n; i++) {
44                     if(G[t][i] && G[i][t]) {
45                         System.out.printf(", %s", name.get(i));
46                         vis[i] = true;
47                     }
48                 }
49                 System.out.println();
50             }
51         }
52     }
53
54     public static void main(String args[]) { new Main().MAIN(); }
55 }

原文地址:https://www.cnblogs.com/hkxy125/p/9527686.html

时间: 2024-12-10 02:27:13

UVa 247 - Calling Circles(Floyd求有向图的传递闭包)的相关文章

uva 247 Calling Circles(Floyd 的简单应用)

最近在看图论的经典算法, 先看的是求单源最短路的dijkstra,优化后的算法用了优先队列,看起来有点复杂. 感觉 弗洛伊德(Floyd) 要比 迪克斯特拉(dijkstra) 更好理解一点,但是Floyd是三层循环,当然会慢很多.一旦数据开大就跪了吧. floyd可以用来求 两个 连通点间的最短路问题.同时可以得到边权的和,即最短路的长度. 另外一个比较简单的应用,还可以用来判断两点间的连通性.即判断两点是否连通.本题就是弗洛伊德的这种简单用法. #include<cstdio> #incl

11.3.4 例题11-4 UVA 247 Calling Circles (有向图的传递闭包)

题目大意: 给你n个人,m条边,a->b,b->a,才能说这两个人是联通的.问现在有多少个联通圈.输出每个联通圈.n<=25 解题思路: 直接建图,用有向图的闭包传递特性来处理每个人之间的联通关系.然后dfs一次,遍历邻接矩阵中与某个点相连的几个点,边遍历, 边打印输出. 代码: # include<cstdio> # include<iostream> # include<map> # include<cstring> # include

UVa 247 Calling Circles【传递闭包】

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

【UVA】247 - Calling Circles(floyd判断包闭,dfs输出)

最近状态不佳,总是爱犯低级错误,比较水的题,没什么需要讲得,要说的可能是floyd判断包闭吧 void Floyd() { for(int k=1; k<=n; k++) for(int i=1; i<=n; i++) if(map[i][k]) for(int j=1; j<=n; j++) if(map[k][j]) map[i][j] = 1; } 之前做了不少图论,图论周感觉能应付的过去. 14059727 247 Calling Circles Accepted C++ 0.0

247 - Calling Circles (Floyd 求传递闭包)

该题恰好用到刚刚讲到的Floyd求传递闭包 , 因为该题的数据量不是很大, 要是大了估计就要用其他方法了 .  但是这毕竟是一个很简单易写的算法 . 求出传递闭包之后就用并查集将在一个电话圈的人合并在一起,最后输出 . 细节参见代码: #include<bits/stdc++.h> using namespace std; int n,m,d[30][30],par[30],kase = 0; string s1,s2; map<string , int > p; map<i

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

bzoj 1027 floyd求有向图最小环

结合得好巧妙.... 化简后的问题是: 给你两个点集A,B,求B的一个子集BB,使得BB的凸包包含A的凸包,求BB的最小大小. 先特判答案为1,2的情况,答案为3的情况,我们先构造一个有向图: 对于B集合中的两个点u,v,如果 所有A集合的点都在u->v的左侧,那么就连一条u->v的边. 于是我们可以证明一个包含A的凸包和我们连出来的有向图中的环一一对应(不考虑点数小于等于2的情况). 于是现在我们的问题就是求最小的一个环,用floyd搞,最后统计min(f[i][i]). 1 /******

UVa 247 (传递闭包) Calling Circles

题意: 有n个人m通电话,如果有两个人相互打电话(直接或间接)则在同一个电话圈里.输出所有电话圈的人的名单. 分析: 根据打电话的关系,可以建一个有向图,然后用Warshall算法求传递闭包. 最后输出是辅助一个标记数组,用DFS输出的,这个办法挺巧妙的. 本来我原来的想法是,用并查集求所有的连通分量,然后再好多次循环找连通分量一致的名字输出,那样太麻烦了. ios::sync_with_stdio(false);这个最好不要随便用,可能会产生某些副作用. 字符指针是可以传给string对象作参

World Finals 1996 Uva (Floyd求闭包)

思路:用Floyd求传递闭包. 附:逗号后的空格没看到,WA了好多次…….还有就是强连通分量也可以做,但是对这个题来说太麻烦,而且不方便输出,. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<map> using namespace std; int n,m; map<string,int> ma; map&l