hdu2767&&hdu3836 Proving Equivalences(Tarjan+缩点)
来源:互联网 发布:软件板块股票行情 编辑:程序博客网 时间:2024/06/06 05:24
http://acm.hdu.edu.cn/showproblem.php?pid=2767
题意:给你n个命题,m个推导,求增加多少条推导就能使命题两两等价。
ps:这里终于看懂九野巨的模板了,刚开始就是边的输入方式不懂,怎么模拟都不对。后来一想,这尼玛是头插法啊,我就说怎么似曾相识。看来我数据结构水的一比啊。也好,让自己复习下数据结构。
思路:命题转化为节点,推导转化为边,求再增加多少条边就可以将其变为强连通图。不同于上一道题判断是否为连通图,这题求的是添加的边数。这里采用了把强连通分量转化为缩点,这样就变成了有向无环图。连接有向无环图中入度为0与出度为0的点,相当于入度为0的有root个点,出度为0的有leaf个点,统计数量。因为肯定有剩余的,而剩余的乱连就行,而乱连也不会影响其连通性,所以要求最大值。关于缩点详解,看的这篇博客。主要就是将其染色,不同颜色的累加到需要连接的数组中,便于统计。
#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <string.h>#include <iostream>#include <stack>#include <vector>using namespace std;typedef long long LL;const int N = 100010;const int INF = 1e8;stack<int>S;int dfn[N], low[N], head[N], Belong[N], in[N], out[N], countt, time, n, m, pos;bool instack[N];struct Edge{ int to, next;}edge[N];void add(int u, int v){ edge[pos].to = v; edge[pos].next = head[u]; head[u] = pos++;}void init(){ time = countt = pos = 0; memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(head, -1, sizeof(head)); memset(instack, false, sizeof(instack));}void Tarjan(int u){ int v; dfn[u] = low[u] = ++time; instack[u] = true; S.push(u); for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(dfn[v] == 0) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(instack[v] == 1) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { countt ++; do { v = S.top(); S.pop(); instack[v] = false; Belong[v] = countt; }while(u != v); }}int main(){ // freopen("in.txt", "r", stdin); int t, u, v; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); init(); for(int i = 1; i <= m; i++) { scanf("%d%d", &u, &v); add(u, v); } //缩点 for(int i = 1; i <= n; i++) { if(dfn[i] == 0) Tarjan(i); } if(countt == 1) { printf("0\n"); continue; } for(int i = 1; i <= n; i++) { for(int k = head[i]; k != -1; k = edge[k].next) { int j = edge[k].to; if(Belong[i] != Belong[j]) { out[Belong[i]]++; in[Belong[j]]++; } } } //找叶子和根度为0的数量 int root = 0, leaf = 0; for(int i = 1; i <= countt; i++) { if(in[i] == 0) root++; if(out[i] == 0) leaf++; } printf("%d\n", max(root, leaf)); } return 0;}
顺便贴上hdu3836,代码几乎一毛一样。
#include <stdio.h>#include <algorithm>#include <stdlib.h>#include <string.h>#include <iostream>#include <stack>#include <vector>using namespace std;typedef long long LL;const int N = 100010;const int INF = 1e8;stack<int>S;int dfn[N], low[N], head[N], Belong[N], in[N], out[N], countt, time, n, m, pos;bool instack[N];struct Edge{ int to, next;}edge[N];void add(int u, int v){ edge[pos].to = v; edge[pos].next = head[u]; head[u] = pos++;}void init(){ time = countt = pos = 0; memset(in, 0, sizeof(in)); memset(out, 0, sizeof(out)); memset(dfn, 0, sizeof(dfn)); memset(low, 0, sizeof(low)); memset(head, -1, sizeof(head)); memset(instack, false, sizeof(instack));}void Tarjan(int u){ int v; dfn[u] = low[u] = ++time; instack[u] = true; S.push(u); for(int i = head[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(dfn[v] == 0) { Tarjan(v); low[u] = min(low[u], low[v]); } else if(instack[v] == 1) { low[u] = min(low[u], dfn[v]); } } if(dfn[u] == low[u]) { countt ++; do { v = S.top(); S.pop(); instack[v] = false; Belong[v] = countt; }while(u != v); }}int main(){ // freopen("in.txt", "r", stdin); int u, v; while(~scanf("%d%d", &n, &m)) { init(); for(int i = 1; i <= m; i++) { scanf("%d%d", &u, &v); add(u, v); } //缩点 for(int i = 1; i <= n; i++) { if(dfn[i] == 0) Tarjan(i); } if(countt == 1) { printf("0\n"); } else { for(int i = 1; i <= n; i++) { for(int k = head[i]; k != -1; k = edge[k].next) { int j = edge[k].to; if(Belong[i] != Belong[j]) { out[Belong[i]]++; in[Belong[j]]++; } } } //找叶子和根度为0的数量 int root = 0, leaf = 0; for(int i = 1; i <= countt; i++) { if(in[i] == 0) root++; if(out[i] == 0) leaf++; } printf("%d\n", max(root, leaf)); } } return 0;}
0 0
- hdu2767&&hdu3836 Proving Equivalences(Tarjan+缩点)
- [HDU2767]Proving Equivalences(Tarjan缩点)
- [HDU2767]Proving Equivalences(Tarjan缩点+强连通分量)
- hdu2767 Proving Equivalences(缩点)
- HDU2767 Proving Equivalences 解题报告【tarjan缩点】
- hdu2767 Proving Equivalences(强连通,缩点)
- hdu2767 Proving Equivalences 强连通(缩点染色)
- HDU 2767 Proving Equivalences(强连通 Tarjan+缩点)
- 【HDU 2767】Proving Equivalences (Tarjan 缩点)
- HDU 2767 Proving Equivalences(强连通 Tarjan+缩点)
- hdu 2767 Proving Equivalences (tarjan + 缩点)
- hdu 2767 Proving Equivalences //tarjan+缩点
- HDU2767 Proving Equivalences
- hdu2767 Proving Equivalences
- HDU2767 Proving Equivalences
- HDU2767 Proving Equivalences
- HDU2767 Proving Equivalences 强连通 Tarjan 缩点成树 统计
- HDU3836 Tarjan缩点
- java基础学习总结——面向对象
- HTML总结
- Codeforces Round #353 (Div. 2)E
- Linux下安装VMware Tools 的方法
- 基于注解的组件扫描
- hdu2767&&hdu3836 Proving Equivalences(Tarjan+缩点)
- laravel5.1框架下实现图片上传
- Linux日常维护命令
- ViewPager + Fragment 获取Tag
- SSM小技巧(一)、Controller中互相调用session中存储的内容
- OC 对象作为方法的参数连续传递
- ZOJ 3228Searching the String
- MySQL入门--修改mysql提示符的两种方法
- 编程之美3:最大公约数问题