【强连通分量模板题 && 加几条边变强连通】POJ
来源:互联网 发布:淘宝 分布式系统架构 编辑:程序博客网 时间:2024/06/18 10:17
Problem Description
给你N个学校的网络,接下来N行,每行输出整数,以0退出。代表第i个学校的网络能到达这n个整数。(1)要你输出至少需要几个学校网络就可以遍布所有学校网络。(2)如果想学校网络能够两两相互到达至少需要加几条边(其实就是将整个图变成强连通需要加几条边)
思路:求出强连通分量缩点(DAG图),(1)入度为0的点的个数代表第一问题的答案。(2)找出入度为0点的最大个数,出度的为0点的最大个数,取两者最大的就是 需要加的边数(特例 只有一个强连通的时候,出度为0的点和入度为0的点就是本身只有一个。但是已经满足要求不需要加边了。所以另外讨论)
//Kosaraju#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct node{ int to, next, fo, next2;};node Map[100 * 100];int head[105], head2[105], n;int vis[105], num[105], scc[105];void dfs(int u, int &sig)//正向dfs 求num[]数组{ vis[u] = 1; for(int i = head[u]; ~i; i = Map[i].next) { if(!vis[Map[i].to]) dfs(Map[i].to, sig); } num[++sig] = u;}void rdfs(int u, int sig)//num[]越后存图的点越先dfs,这样跑的dfs得到的所有点的集合就是一个连通分量(因为越后面的点反向图后,dfs能跑的点也就是两两能到达的点){ vis[u] = 1; scc[u] = sig;//记录该点对应 第几个强连通分量 for(int i = head2[u]; ~i; i = Map[i].next2) { if(!vis[Map[i].fo]) { rdfs(Map[i].fo, sig); } }}int Kosaraju()//求强连通分量{ memset(vis, 0, sizeof(vis)); int sig = 0, i; for(i = 1; i <= n; i++) { if(!vis[i]) dfs(i, sig); } memset(vis, 0, sizeof(vis)); sig = 1; for(i = n; i > 0; i--) { if(!vis[num[i]]) { rdfs(num[i], sig++); } } return sig;//所有的强连通分量(包括一个点)}void add(int u, int v, int &cnt)//前向星存图,正向,反向{ Map[cnt].to = v; Map[cnt].next = head[u]; head[u] = cnt; Map[cnt].fo = u; Map[cnt].next2 = head2[v]; head2[v] = cnt++;}int main(){ int i, cnt, v; int l[100 * 100], r[100 * 100]; int out[105], in[105]; while(~scanf("%d", &n)) { memset(out, 0, sizeof(out));//初始化 memset(in, 0, sizeof(in)); cnt = 0; memset(head, -1, sizeof(head)); memset(head2, -1, sizeof(head2)); int m = 0; for(i = 1; i <= n; i++) { while(~scanf("%d", &v) && v) { l[m] = i; r[m++] = v;//拿数组记录下来 那个网络到那个网络 add(i, v, cnt); } } int N = Kosaraju();//求出DAG图 for(i = 0; i < m; i++) { if(scc[l[i]] != scc[r[i]])//相等代表同一个强连通分量,不需要考虑 { out[scc[l[i]]]++;//记录出度 in[scc[r[i]]]++;//记录入度 } } int ans1 = 0, ans2 = 0; for(i = 1; i < N; i++)//遍历一遍所有强连通分量 { if(!out[i]) ans1++;//出度为0的点 if(!in[i]) ans2++;//入度为0的点 } if(N == 2) printf("1\n0\n");//代表强连通分量只有一个特判 else { printf("%d\n", ans2);//入度为0的点 printf("%d\n", max(ans1, ans2));//取最大 } } return 0;}
//tarjan#include<cstdio>#include<cstring>#include<algorithm>using namespace std;struct node{ int to, next;};node Map[100 * 100];int head[105], n;int vis[105], dfn[105], low[105], scc_num, lay, m;//dfn[]数组不改变用来记录该点,访问时间(被遍历的顺序)。(时间戳)//low[]记录的是点v可以到达的访问时间最早的祖先//vis[] 用来记录该点属于第几个强连通分量int st[105];void tardfs(int u){ low[u] = lay; dfn[u] = lay++; st[++m] = u;//到那个点,那个点就入栈 for(int i = head[u]; ~i; i = Map[i].next) { int to = Map[i].to; if(!dfn[to]) {//没有走过的点,继续dfs tardfs(to); low[u] = min(low[u], low[to]); } else if(!vis[to]) low[u] = min(low[u], dfn[to]);//可以到达访问时间最早的祖先 } if(dfn[u] == low[u])//这时候缩点 { ++scc_num; do { vis[st[m]] = scc_num;//将构成强连通分量的点缩成scc_num }while(st[m--] != u); }}int tarjan(){ scc_num = 0, lay = 1;//scc_num用来记录有几个强连通分量 m = 0; memset(vis, 0, sizeof(vis));//初始化 memset(low, 0, sizeof(low)); for(int i = 1; i <= n; i++)//遍历一遍 { if(!vis[i]) tardfs(i); } return scc_num;}void add(int u, int v, int &cnt)//前向星存图{ Map[cnt].to = v; Map[cnt].next = head[u]; head[u] = cnt++;}int main(){ int i, cnt, v; int l[100 * 100], r[100 * 100]; int out[105], in[105]; while(~scanf("%d", &n)) { memset(out, 0, sizeof(out)); memset(in, 0, sizeof(in)); cnt = 0; memset(head, -1, sizeof(head)); int m = 0; for(i = 1; i <= n; i++) { while(~scanf("%d", &v) && v) { l[m] = i; r[m++] = v; add(i, v, cnt); } } int N = tarjan(); for(i = 0; i < m; i++) { if(vis[l[i]] != vis[r[i]]) { out[vis[l[i]]]++;//出度 in[vis[r[i]]]++; } } int ans1 = 0, ans2 = 0; for(i = 1; i <= N; i++) { if(!out[i]) ans1++; if(!in[i]) ans2++; } if(N == 1) printf("1\n0\n"); else { printf("%d\n", ans2); printf("%d\n", max(ans1, ans2)); } } return 0;}
阅读全文
0 0
- 【强连通分量模板题 && 加几条边变强连通】POJ
- 强连通分量模板
- 强连通分量模板
- 强连通分量模板
- 强连通分量 模板
- 强连通分量模板
- 强连通分量模板
- 强连通分量模板
- 【强连通分量模板】
- 【模板】强连通分量
- 强连通分量模板
- poj 2186 tarjan求强连通分量(模板题)
- POJ 2186 Popular Cows(强连通分量模板题)
- 强连通分量Tarjan模板
- 强连通分量(模板)
- Tarjan强连通分量模板
- POJ 2186 强连通分量
- poj 1236【强连通分量】
- 文件操作函数
- windows常用快捷键总结
- 【图论】模板总结
- 2.1.7 —线性表—Two Sum
- hdu(6063)2017多校水题
- 【强连通分量模板题 && 加几条边变强连通】POJ
- [总结]C语言真是博大精深(二)
- mysql int bigint
- JavaScript语法
- MPI Maelstrom
- echart 基本设置
- Velocity模板引擎的简单使用
- VLDB summer school(一)近似查询处理2——数学基础
- Android Studio在创建/导入项目的时候,一直处于building “XXX”gradle project info的解决办法