POJ-1236(有向图强连通分量 + 缩点 + 加边使得整个图强连通)
2014-08-14 15:48
501 查看
题目:http://poj.org/problem?id=1236
感觉是强连通问题的一道典型题目,还是有很多地方没有注意到,看了discuss才发现:
(1)当整个图已经是一个SCC时
(2)对于SCC缩点后的DAG,实际上等于问我们需要加多少条有向边,使得整个DAG变为强连通,因此,我们要给每个入度为0的点(设有A个)加一条入边,给每个出度为0的点(设有B个)加一条出边,而这些加上的边有重合,那到底要加几条呢,实际上是max(A, B)个
感觉是强连通问题的一道典型题目,还是有很多地方没有注意到,看了discuss才发现:
(1)当整个图已经是一个SCC时
(2)对于SCC缩点后的DAG,实际上等于问我们需要加多少条有向边,使得整个DAG变为强连通,因此,我们要给每个入度为0的点(设有A个)加一条入边,给每个出度为0的点(设有B个)加一条出边,而这些加上的边有重合,那到底要加几条呢,实际上是max(A, B)个
#include <cstdio> #include <cstring> #include <vector> #include <stack> #include <algorithm> using namespace std; #define MAX 101 int N, dfsClock, pre[MAX]; int sccCnt, sccno[MAX], sccOutDegree[MAX], sccInDegree[MAX]; vector<int> list[MAX], scc[MAX]; stack<int> st; int dfs(int x) { int lowx, y, lowy; const vector<int>& v = list[x]; lowx = pre[x] = ++dfsClock; st.push(x); for(int i = 0, n = v.size(); i < n; ++i){ y = v[i]; if(!pre[y]){ lowy = dfs(y); lowx = min(lowx, lowy); } else if(!sccno[y]) lowx = min(lowx, pre[y]); } if(lowx == pre[x]){ ++sccCnt; scc[sccCnt].clear(); while(true){ y = st.top(); st.pop(); sccno[y] = sccCnt; scc[sccCnt].push_back(y); if(y == x) break; } } return lowx; } void findScc() { memset(pre + 1, 0, N << 2); memset(sccno + 1, 0, N << 2); dfsClock = sccCnt = 0; for(int i = 1; i <= N; ++i){ if(!pre[i]) dfs(i); } } void findSccInOutDegree() { bool out[MAX]; memset(sccInDegree + 1, 0, sccCnt << 2); for(int i = 1; i <= sccCnt; ++i){ memset(out + 1, false, sccCnt); int degree = 0; const vector<int>& v = scc[i]; for(int j = 0, n = v.size(); j < n; ++j){ const vector<int>& l = list[v[j]]; for(int k = 0, m = l.size(); k < m; ++k){ int no = sccno[l[k]]; if(no != i && !out[no]){ out[no] = true; ++degree; ++sccInDegree[no]; } } } sccOutDegree[i] = degree; } } void solve() { findScc(); findSccInOutDegree(); if(sccCnt == 1){ puts("1\n0"); return; } int noInScc = 0, noOutScc = 0; for(int i = 1; i <= sccCnt; ++i){ if(!sccInDegree[i]) ++noInScc; if(!sccOutDegree[i]) ++noOutScc; } printf("%d\n%d\n", noInScc, max(noInScc, noOutScc)); } bool input() { if(1 != scanf("%d", &N)) return false; int j; for(int i = 1; i <= N; ++i){ list[i].clear(); while(scanf("%d", &j), j){ list[i].push_back(j); } } return true; } int main() { while(input()) solve(); return 0; }
相关文章推荐
- 强连通分量,Tarjan,缩点(Network of Schools,POJ 1236)
- Network of Schools POJ - 1236 tarjan强连通分量缩点
- 【强连通分量缩点】poj 1236 Network of Schools
- POJ 1236 Network Of Schools ( tarjan求强连通分量 + 缩点成DAG图 )
- poj 1236 scc强连通分量
- POJ 1236 Network of Schools(强连通 Tarjan+缩点)
- POJ 1236 Network of Schools(Tarjan Algorithm求强连通子集,缩点后DAG上出或入度为0的点)
- poj1236强连通缩点
- poj-1236-一起学习强连通分量
- poj1236强连通缩点
- POJ 2186 Popular Cows(强连通分量缩点,Tarjan算法)
- poj 1236 Network of Schools(强连通、缩点、出入度)
- poj 1236 Network of Schools (强连通分支缩点)
- poj-1236--一起学习强连通分量2
- poj 2186 Popular Cows(Tarjan,强连通分量缩点)
- POJ 1236 Network of Schools(强连通 Tarjan+缩点)
- POJ 1236 Network of Schools(强连通缩点)
- POJ 1236 Network of Schools ★(经典问题:强联通分量+缩点)
- POJ 1236 Network of Schools ★(经典问题:强联通分量+缩点)
- POJ-1236 Network of Schools 强连通+缩点