Wannafly挑战赛14C可达性Tarjan缩点
Posted MekakuCityActor
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Wannafly挑战赛14C可达性Tarjan缩点相关的知识,希望对你有一定的参考价值。
链接:https://www.nowcoder.com/acm/contest/81/C
来源:牛客网
题目描述
给出一个 0 ≤ N ≤ 105 点数、0 ≤ M ≤ 105 边数的有向图,
输出一个尽可能小的点集,使得从这些点出发能够到达任意一点,如果有多个这样的集合,输出这些集合升序排序后字典序最小的。
输入描述:
第一行为两个整数 1 ≤ n, m ≤ 10^5
接下来 M 行,每行两个整数 1 ≤ u, v ≤ 10^5
表示从点 u 至点 v 有一条有向边。
数据保证没有重边、自环。
输出描述:
第一行输出一个整数 z,表示作为答案的点集的大小;
第二行输出 z 个整数,升序排序,表示作为答案的点集。
示例1
输入
7 10
4 5
5 1
2 5
6 5
7 2
4 2
1 2
5 3
3 5
3 6
输出
2
4 7
题目大意:给一个有向图,求最少以哪几个点为起点能遍历全图
题目分析:由于强连通分量内的所有点都能走到彼此,所以可以先求出所有的强连通分量来进行缩点并且重构缩点之后的图。
【所谓缩点就是将整个连通块内化为一个点来进行操作,具体缩点操作就是求出连通块之后遍历所有边,把连通块看作是点,将连接不同连通块的边当作缩点之后的边】
由重构之后的图可知,入度不为0的"点"【也就是缩点之后的连通块】不需要取任何连通块内部的点就能被遍历到,所以只需在入度为0的"点"【连通块】找到字母序最小的内部点。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=100005; 4 struct edge{ 5 int from; 6 int to; 7 int next; 8 }EDGE[maxn]; 9 vector<int>vc[maxn]; 10 int head[maxn],dfn[maxn],vis[maxn],low[maxn],col[maxn],in[maxn],en[maxn],stk[maxn]; 11 int edge_cnt=1,tot1=1,tot2=0,scc_cnt=0,tot0=0; 12 void add(int x,int y) 13 { 14 EDGE[edge_cnt].from=x; 15 EDGE[edge_cnt].to=y; 16 EDGE[edge_cnt].next=head[x]; 17 head[x]=edge_cnt++; 18 } 19 void Tarjan(int u) 20 { 21 low[u]=dfn[u]=tot1++; 22 vis[u]=1; 23 stk[++tot2]=u; 24 for(int i = head[u]; i != -1 ; i = EDGE[i].next) 25 { 26 if(!dfn[EDGE[i].to]){ 27 Tarjan(EDGE[i].to); 28 low[u]=min(low[u],low[EDGE[i].to]); 29 } 30 else if(vis[EDGE[i].to]){ 31 low[u]=min(low[u],low[EDGE[i].to]); 32 } 33 } 34 if(low[u]==dfn[u]){ 35 int xx; 36 scc_cnt++; 37 do{ 38 xx=stk[tot2--]; 39 vc[scc_cnt].push_back(xx); 40 col[xx]=scc_cnt; 41 vis[xx]=0; 42 }while(xx!=u); 43 } 44 } 45 int main() 46 { 47 int n,m; 48 scanf("%d%d",&n,&m); 49 memset(head,-1,sizeof(head)); 50 memset(in,0,sizeof(in)); 51 while(m--) 52 { 53 int a,b; 54 scanf("%d%d",&a,&b); 55 add(a,b); 56 } 57 for(int i = 1 ; i <= n; i++) 58 { 59 if(!dfn[i])Tarjan(i); 60 } 61 for(int i = 1 ; i <= edge_cnt ; i++) 62 { 63 if(col[EDGE[i].from]!=col[EDGE[i].to]) 64 { 65 in[col[EDGE[i].to]]++; 66 } 67 } 68 for(int i = 1 ; i <= scc_cnt ; i++) 69 { 70 if(in[i]) 71 continue; 72 int mmin=vc[i][0]; 73 for(int j = 1 ; j < vc[i].size() ; j++) 74 { 75 if(vc[i][j]<mmin) 76 mmin=vc[i][j]; 77 } 78 en[tot0++]=mmin; 79 } 80 81 printf("%d\n",tot0); 82 sort(en,en+tot0); 83 for(int i = 0 ; i < tot0 ; i++) 84 { 85 printf("%d",en[i]); 86 char c=(i==tot0-1)?‘\n‘:‘ ‘; 87 printf("%c",c); 88 } 89 return 0; 90 } 91 /*4 5 92 1 3 93 2 4 94 4 2 95 1 4 96 2 1*/
以上是关于Wannafly挑战赛14C可达性Tarjan缩点的主要内容,如果未能解决你的问题,请参考以下文章
强连通分量tarjan缩点——POJ2186 Popular Cows