POJ 2186 Popular Cows——Tarjan缩点
原创
©著作权归作者所有:来自51CTO博客作者软糖酱八号机的原创作品,请联系作者获取转载授权,否则将追究法律责任
题意:有n头牛,m个崇拜关系,并且崇拜具有传递性,如果a崇拜b,b崇拜c,则a崇拜c,求最后有几头牛被所有牛崇拜。
思路:
显然一个强联通分量内的所有点都是满足条件的,我们可以对整张图进行缩点,然后就简单了。
剩下的所有点都不是强连通的,现在整张图就是一个DAG(有向无环图)
那么就变成一道水题了,因为这是一个有向无环图,不存在所有点的出度都不为零的情况。
所以必然有1个及以上的点出度为零,如果有两个点出度为零,那么这两个点肯定是不相连的,即这两圈牛不是互相崇拜的,于是此时答案为零,如果有1个点出度为0,那么这个点就是被全体牛崇拜的,
这个点可能是一个强联通分量缩成的超级点,所以应该输出整个强联通分量中点的个数。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1e4 + 10;
const int maxm = 5e4 + 10;
int dfn[maxn], low[maxn], vis[maxn], stack[maxn], color[maxn];
int du[maxn], cnt[maxn];
int n, m, top, C, deep;
int mem, head[maxn];
struct Edge { int to, next; } edges[maxm];
void addedge(int u, int v) {
++mem;
edges[mem].to = v, edges[mem].next = head[u];
head[u] = mem;
}
void tarjan(int u) {
dfn[u] = low[u] = ++deep;
vis[u] = 1;
stack[++top] = u;
for (int i = head[u]; ~i; i = edges[i].next) {
int v = edges[i].to;
if (!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
}
else {
if (vis[v]) {
low[u] = min(low[u], low[v]);
}
}
}
if (dfn[u] == low[u]) {
color[u] = ++C;
vis[u] = 0;
while (stack[top] != u) {
color[stack[top]] = C;
vis[color[top--]] = 0;
}
top--;
}
}
int main() {
while (~scanf("%d%d", &n, &m)) {
for (int i = 0; i <= n; i++) {
dfn[i] = low[i] = 0;
vis[i] = color[i] = 0;
du[i] = cnt[i] = 0;
head[i] = -1;
}
mem = top = C = deep = 0;
for (int i = 1; i <= m; i++) {
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
}
for (int i = 1; i <= n; i++) {
if (!dfn[i]) tarjan(i);
}
for (int i = 1; i <= n; i++) {
for (int j = head[i]; ~j; j = edges[j].next) {
int v = edges[j].to;
if (color[v] != color[i]) {
du[color[i]]++;
}
}
cnt[color[i]]++;
}
int ans = 0;
int temp = 0;
for (int i = 1; i <= C; i++) {
if (du[i] == 0) {
temp++;
ans = cnt[i];
}
}
if (temp == 1) printf("%d\n", ans);
else printf("0\n");
}
return 0;
}