POJ 2186 Popular Cows(强连通分量缩点)
题目链接:http://poj.org/problem?id=2186
题目意思大概是:给定N(N<=10000)个点和M(M<=50000)条有向边,求有多少个“受欢迎的点”。所谓的“受欢迎的点”当且仅当任何一个点出发都能到达它。
原来的图是无序且可能有环,用tarjan缩点,变成一个DAG。受欢迎点的出度一定为0,所以缩点后求有多少个连通分量的出度是0,要是大于1则没有受欢迎的点,等于1的话求出这个出度为0的连通分量有多少个点。
强联通分量tarjan算法里邻接表用vector一般好理解,但是速度不及链式前向星,链式前向星学习链接:http://blog.csdn.net/acdreamers/article/details/16902023
AC代码如下:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 5 using namespace std; 6 const int MAXN = 1e4 + 5; 7 struct data { 8 int next , to; 9 }edge[MAXN * 5]; 10 int head[MAXN] , low[MAXN] , dfn[MAXN] , block[MAXN] , st[MAXN]; 11 int top , ord , sccnum; 12 bool instack[MAXN] , out[MAXN]; 13 14 void init(int n) { 15 for(int i = 1 ; i <= n ; i++) { 16 low[i] = dfn[i] = 0; 17 head[i] = -1; 18 instack[i] = false; 19 } 20 top = ord = sccnum = 0; 21 } 22 23 void tarjan(int u) { 24 low[u] = dfn[u] = ++ord; 25 st[++top] = u; 26 instack[u] = true; 27 for(int i = head[u] ; ~i ; i = edge[i].next) { //链式前向星 28 int v = edge[i].to; 29 if(!dfn[v]) { 30 tarjan(v); 31 low[u] = min(low[u] , low[v]); 32 } 33 else if(instack[v]) { 34 low[u] = min(low[u] , dfn[v]); 35 } 36 } 37 if(low[u] == dfn[u]) { 38 int v; 39 sccnum++; 40 do { 41 v = st[top--]; 42 instack[v] = false; 43 block[v] = sccnum; 44 }while(u != v); 45 } 46 } 47 48 int main() 49 { 50 int n , m , u , v; 51 while(~scanf("%d %d" , &n , &m)) { 52 init(n); 53 for(int i = 0 ; i < m ; i++) { 54 scanf("%d %d" , &u , &v); 55 edge[i].to = v; //链式前向星 56 edge[i].next = head[u]; 57 head[u] = i; 58 } 59 for(int i = 1 ; i <= n ; i++) { 60 if(!dfn[i]) 61 tarjan(i); 62 } 63 memset(out , false , sizeof(out)); //缩点是否有入度 64 for(int u = 1 ; u <= n ; u++) { 65 for(int i = head[u] ; ~i ; i = edge[i].next) { //链式前向星 66 int v = edge[i].to; 67 if(block[v] != block[u]) //不是同一个连通分量 68 out[block[u]] = true; 69 } 70 } 71 int res = 0 , op = -1; 72 for(int i = 1 ; i <= sccnum ; i++) { 73 if(!out[i]) { //出度为0的点 74 res++; 75 op = i; 76 } 77 } 78 if(res > 1) { 79 printf("0\n"); 80 } 81 else { 82 res = 0; 83 for(int i = 1 ; i <= n ; i++) { 84 if(block[i] == op) 85 res++; 86 } 87 printf("%d\n" , res); 88 } 89 } 90 }