LA-4287 & HDOJ-2767 Proving Equivalences 解题报告
2014-11-24 20:46
465 查看
强连通分量题。题意:在数学中经常需要完成若干个命题的等价证明。比如有4个命题a,b,c,d,我们从a证明到b,从b证明到a,然后b到c,c到b,最后c到d,d到c。这样就证明了4个命题等价,当然也可以这样证明,从a到b,b到c,c到d,d到a。任务是要求证明n个命题全部等价,现在已经完成了m次证明,问最少还需要几次证明就可以完成整个证明?
我的解题思路:将每一个命题看做一个节点,那么n个命题等价则说明这n个节点所构成的图强连通。要使原图强连通,先算一下原图中强连通分量的个数。再判断一下出度为0的强连通分量个数x和入度为0的强连通分量个数y,那么最少需要max(x, y)次证明才能使原图强连通。注意:假如原图已经强连通(原图强连通分量个数为1),那么就说明这n个命题已经是等价的了。
我的解题代码:强连通分量Tarjan算法+缩点
我的解题思路:将每一个命题看做一个节点,那么n个命题等价则说明这n个节点所构成的图强连通。要使原图强连通,先算一下原图中强连通分量的个数。再判断一下出度为0的强连通分量个数x和入度为0的强连通分量个数y,那么最少需要max(x, y)次证明才能使原图强连通。注意:假如原图已经强连通(原图强连通分量个数为1),那么就说明这n个命题已经是等价的了。
我的解题代码:强连通分量Tarjan算法+缩点
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <vector> #include <queue> using namespace std; #define N 30003 vector <int> e ; int dfn , low ; int stack , stop; int vis ; int belong ; int timer; int sccn; int indeg ; int outdeg ; int n, m; void InitRead(); void DataProcess(); void Tarjan(int x); int main() { int t; scanf("%d", &t); while (t--) { InitRead(); DataProcess(); } return 0; } void InitRead() { scanf("%d %d", &n, &m); memset(vis, 0, sizeof(vis)); memset(indeg, 0, sizeof(indeg)); memset(outdeg, 0, sizeof(outdeg)); stop = timer = sccn = 0; for (int i=1; i<=n; ++i) e[i].clear(); int a, b; for (int i=0; i<m; ++i) { scanf("%d %d", &a, &b); e[a].push_back(b); } return; } void DataProcess() { for (int i=1; i<=n; ++i) { if (!vis[i]) { Tarjan(i); } } if (sccn == 1) //特判,假如原图已经强连通,那么不需要继续证明了 { puts("0"); return; } for (int i=1; i<=n; ++i) { int size = e[i].size(); for (int j=0; j<size; ++j) { if (belong[i] != belong[e[i][j]]) { outdeg[belong[i]]++; indeg[belong[e[i][j]]]++; } } } int ansin = 0, ansout = 0; for (int i=1; i<=sccn; ++i) { if (outdeg[i] == 0) ansout++; if (indeg[i] == 0) ansin++; } printf("%d\n", max(ansin, ansout)); return; } void Tarjan(int x) { int y; dfn[x] = low[x] = ++timer; stack[stop++] = x; vis[x] = 2; int size = e[x].size(); for (int i=0; i<size; ++i) { y = e[x][i]; if (!vis[y]) { Tarjan(y); low[x] = min(low[x], low[y]); } else if (vis[y] == 2) { low[x] = min(low[x], dfn[y]); } } if (dfn[x] == low[x]) { sccn++; do { y = stack[--stop]; vis[y] = 1; belong[y] = sccn; } while (x != y); } return; }
相关文章推荐
- LA-2523 & POJ-1325 & HDOJ-1150 Machine Schedule 解题报告
- HDOJ-1160-FatMouse's Speed 解题报告
- LA-3883 & POJ-3518 Prime Gap 解题报告
- HDOJ-5023-A Corrupt Mayor's Performance Art 解题报告
- LA-3415 & POJ-2771 Guardian of Decency 解题报告
- POJ-1411 & HDOJ-1239 Calling Extraterrestrial Intelligence Again 解题报告
- HDOJ_1480 钥匙计数之二 解题报告(…
- HDOJ-1397-Goldbach's Conjecture 解题报告
- HDOJ-1164-Eddy's research I 解题报告
- POJ-1142 & HDOJ-1333 Smith Numbers 解题报告
- LA-3399 & POJ-2739 Sum of Consecutive Prime Numbers 解题报告
- LA-3938-"Ray, Pass me the dishes!" 解题报告
- POJ-1308 & HDOJ-1325 Is It A Tree? 解题报告
- HDOJ_1160:FatMouse's Speed 解题报告
- 计算方法实验报告(Lagrange&Rounge)
- HDOJ_2050 折线分割平面 解题报告
- poj 2593 & poj 2479解题报告
- HDOJ 1021 Fibonacci Again解题报告
- HDOJ 1020解题报告
- ACM--HDOJ2503解题报告