[POJ1236]Network of Schools(并查集+floyd,伪强连通分量)
2016-05-17 16:44
411 查看
题目链接:http://poj.org/problem?id=1236
这题本来是个强连通分量板子题的,然而弱很久不写tarjan所以生疏了一下,又看这数据范围觉得缩点这个事情可以用点到点之间的距离来判断不知道群巨兹磁不兹磁……下面弱就给大家搞一发如何用floyd和并查集来缩点……大致的思路就是先floyd跑出所有距离,然后O(n^2)找两两都可达的点,把它们的关系用并查集来维护。接下来O(n)找并查集里的代表元素。这个时候应当特判一下连通块为1的时候。再O(n^2)找出所有单向边,然后更新所有代表元素的出入度,就完事了…完事了…数据太水所以弱的floyd跑过了,以后不能这么投机了QAQ
这题本来是个强连通分量板子题的,然而弱很久不写tarjan所以生疏了一下,又看这数据范围觉得缩点这个事情可以用点到点之间的距离来判断不知道群巨兹磁不兹磁……下面弱就给大家搞一发如何用floyd和并查集来缩点……大致的思路就是先floyd跑出所有距离,然后O(n^2)找两两都可达的点,把它们的关系用并查集来维护。接下来O(n)找并查集里的代表元素。这个时候应当特判一下连通块为1的时候。再O(n^2)找出所有单向边,然后更新所有代表元素的出入度,就完事了…完事了…数据太水所以弱的floyd跑过了,以后不能这么投机了QAQ
/* ━━━━━┒ギリギリ♂ eye! ┓┏┓┏┓┃キリキリ♂ mind! ┛┗┛┗┛┃\○/ ┓┏┓┏┓┃ / ┛┗┛┗┛┃ノ) ┓┏┓┏┓┃ ┛┗┛┗┛┃ ┓┏┓┏┓┃ ┛┗┛┗┛┃ ┓┏┓┏┓┃ ┛┗┛┗┛┃ ┓┏┓┏┓┃ ┃┃┃┃┃┃ ┻┻┻┻┻┻ */ #include <algorithm> #include <iostream> #include <iomanip> #include <cstring> #include <climits> #include <complex> #include <fstream> #include <cassert> #include <cstdio> #include <bitset> #include <vector> #include <deque> #include <queue> #include <stack> #include <ctime> #include <set> #include <map> #include <cmath> using namespace std; #define fr first #define sc second #define cl clear #define W(a) while(a--) #define pb(a) push_back(a) #define Rint(a) scanf("%d", &a) #define Rll(a) scanf("%I64d", &a) #define Rs(a) scanf("%s", a) #define FRead() freopen("in", "r", stdin) #define FWrite() freopen("out", "w", stdout) #define Rep(i, len) for(int i = 0; i < (len); i++) #define For(i, a, len) for(int i = (a); i < (len); i++) #define Cls(a) memset((a), 0, sizeof(a)) #define Clr(a, x) memset((a), (x), sizeof(a)) #define Full(a) memset((a), 0x7f7f, sizeof(a)) const int inf = 0x7f7f7f; const int maxn = 111; int n, m; int in[maxn], out[maxn]; int dp[maxn][maxn]; int pos[maxn], cnt; int pre[maxn]; int belong[maxn]; int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); } void unite(int x, int y) { x = find(x); y = find(y); if(x != y) pre[x] = y; } int main() { // FRead(); int v; while(~Rint(n)) { Cls(in); Cls(out); For(i, 1, n+1) { pre[i] = i; For(j, 1, n+1) dp[i][j] = inf; dp[i][i] = 0; } For(u, 1, n+1) { while(Rint(v)) { if(v == 0) break; dp[u][v] = 1; } } For(k, 1, n+1) For(i, 1, n+1) For(j, 1, n+1) if(dp[i][j] > dp[i][k] + dp[k][j]) dp[i][j] = dp[i][k] + dp[k][j]; For(i, 1, n+1) { For(j, i+1, n+1) { if(dp[i][j] != inf && dp[j][i] != inf) { unite(i, j); } } } For(i, 1, n+1) { int fa = find(i); if(i == fa) pos[cnt++] = i; belong[i] = fa; } if(cnt == 1) { printf("1\n0\n"); continue; } For(i, 1, n+1) { For(j, 1, n+1) { if(i == j) continue; if(belong[i] != belong[j] && dp[j][i] == inf && dp[i][j] != inf) { in[belong[i]]++; out[belong[j]]++; } } } int ans1 = 0, ans2 = 0; Rep(i, cnt) { if(!out[pos[i]]) ans1++; if(!in[pos[i]]) ans2++; } printf("%d\n%d\n", ans1, max(ans1, ans2)); } return 0; }
相关文章推荐
- 已安装 SQL Server 2005,安装 SQL Server 2008 时提示需要删除 SQL Server 2005 Express 工具
- java实现ftp文件的上传与下载
- iOS判断字符串中是否含有非法字符
- msp430程序跑飞之解决方法
- Kafka安装配置、常用命令
- 自己的选择: Qt VS MFC
- hdu 2363(限制最短路 二分+枚举+最短路)
- Android中使用Notification实现应用更新显示下载进度
- Android Studio 快捷键
- 2016-百度之星-资格赛-Problem A【求逆元】
- Linux权限管理(suid euid)
- iOS8自定义推送显示按钮及推送优化
- jquery autocomplete
- hdu1081 To The Max 「dp」
- java中关于小数的四舍五入问题
- 反转链表
- c语言文件操作总结
- iOS 隐藏系统tabBar及需要push两层时候tabBar的隐藏方法
- Mahout安装与配置,及简单k-means实例
- Git常用命令