POJ 1236 Network of Schools(强连通分量缩点)
2015-09-10 21:27
309 查看
题意:n个学校有向图,得到软件的学校可以根据路径发放给其他学校。问1:至少给几个学校发放。问2:给任意一个学校发放,至少添几条边可发放至所有学校。
显然要用Tarjan先找到所有的强连通分量,然后缩点建树。建树之后对每个缩点记其入度出度。显然,对于问题1,只要向入度为0的点发放软件就可满足条件。
那么问题2呢?试想对于所有的子树,每棵子树有根节点和叶节点,要得到强连通分量,显然需要将这些根节点和叶节点连起来。至少连多少呢?答案是max(根节点个数,叶节点个数)。将一棵树的叶节点连到另一棵树的根节点,就可以完成两棵树的连通,消灭掉叶节点和根节点。消灭掉所有的,就得到了一个强连通分量。至少要多少个,就要看根节点和叶节点哪个多了。
代码:
显然要用Tarjan先找到所有的强连通分量,然后缩点建树。建树之后对每个缩点记其入度出度。显然,对于问题1,只要向入度为0的点发放软件就可满足条件。
那么问题2呢?试想对于所有的子树,每棵子树有根节点和叶节点,要得到强连通分量,显然需要将这些根节点和叶节点连起来。至少连多少呢?答案是max(根节点个数,叶节点个数)。将一棵树的叶节点连到另一棵树的根节点,就可以完成两棵树的连通,消灭掉叶节点和根节点。消灭掉所有的,就得到了一个强连通分量。至少要多少个,就要看根节点和叶节点哪个多了。
代码:
// Header. #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cstdio> #include <vector> #include <string> #include <queue> #include <stack> #include <cmath> #include <set> #include <map> using namespace std; typedef long long LL; #define mem(a, n) memset(a, n, sizeof(a)) #define rep(i, n) for(int i = 0; i < (n); i ++) #define REP(i, t, n) for(int i = (t); i < (n); i ++) #define FOR(i, t, n) for(int i = (t); i <= (n); i ++) #define ALL(v) v.begin(), v.end() #define si(a) scanf("%d", &a) #define sii(a, b) scanf("%d%d", &a, &b) #define siii(a, b, c) scanf("%d%d%d", &a, &b, &c) #define pb push_back const int inf = 0x3f3f3f3f, N = 1e2 + 5, MOD = 1e9 + 7; int T, cas = 0; int n, m; struct edge { int v, next; }e[N * N]; int dfn , low , in , out , head , g , st , vis ; int ne = 0, ans = 0, dfsNum = 0, tot = 0, top = 0, ans1, ans2; void addEdge(int u, int v) { e[ne].v = v; e[ne].next = head[u]; head[u] = ne ++; } // Imp void init() { mem(dfn, 0); mem(low, 0); mem(in, 0); mem(out, 0); mem(st, 0); mem(vis, 0); mem(head, -1); dfsNum = ne = top = tot = 0; } void Tarjan(int u) { dfn[u] = low[u] = ++ dfsNum; st[top++] = u; vis[u] = 1; for(int i = head[u]; i != -1; i = e[i].next) { int v = e[i].v; if(!dfn[v]) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(vis[v]) low[u] = min(low[u], dfn[v]); } if(low[u] == dfn[u]) { tot ++; while(1) { int k = st[--top]; g[k] = tot; vis[k] = 0; if(k == u) break; } } } void work() { ans1 = ans2 = 0; FOR(u, 1, n) { for(int i = head[u]; i != -1; i = e[i].next) { int v = e[i].v; if(g[u] == g[v]) continue; out[g[u]] ++; in[g[v]] ++; } } } void Gao() { work(); FOR(i, 1, tot) { if(!in[i]) ans1 ++; if(!out[i]) ans2 ++; } if(tot == 1) printf("1\n0\n"); else printf("%d\n%d\n", ans1, max(ans1, ans2)); } int main(){ #ifdef LOCAL freopen("/Users/apple/input.txt", "r", stdin); // freopen("/Users/apple/out.txt", "w", stdout); #endif si(n); int v; init(); FOR(u, 1, n) while(si(v), v) addEdge(u, v); FOR(i, 1, n) if(!dfn[i]) Tarjan(i); Gao(); return 0; }
相关文章推荐
- xml有哪些解析技术?区别是什么?
- HTML 元素
- ajax
- Cocos2d-x3.0 RenderTexture(一) 保存
- hdu 1281 二分图残量增广
- 浮点数的表示
- (好题)树状数组+离散化+DFS序+离线/莫队 HDOJ 4358 Boring counting
- Android开发笔记——从SD卡保存和读取文件
- 实用SQL语句大全
- 【1】基于TQ2440的MP3设计——【6、构建根文件系统】
- 视图控制器ViewController的生命周期
- netbean的安装及jdk安装和环境变量设置
- 十进制转二进制、十六进制
- IBM MQTT basic information and support platforms
- 【noip2011】【codevs1135】选择客栈
- VMware 虚拟机使用 NAT 方式联网
- Rust - Arrays and Vectors | 数组和向量
- 正则表达式匹配
- UITableView使用<2>UITableViewCell的介绍
- [最大流]UVa820 - Internet Bandwidth