题目:http://poj.org/problem?id=2186
题意:给一张有向图,求一些点的个数,这些点满足其他所有点都能直接或间接指向它。
方法:tarjan+缩点
View Code
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define Max(A,B) ((A)>(B)?(A):(B))
#define Min(A,B) ((A)<(B)?(A):(B))
#define clr(a,b) memset(a, b, sizeof(a))
using namespace std;
const int MAXV = 10000+10;
const int inf = 0x3f3f3f3f;
const int N = 10010;
const int M = 50010;
int e, ev[M], nxt[M], head[N];
bool instack[N];
int dfn[N], low[N], dindex, q[N], ed;
int belong[N], bcnt;
int cou[N];
bool out[N];
void addedge(int u, int v)
{
ev[e] = v; nxt[e] = head[u]; head[u] = e++;
}
void tarjan(int u)
{
int i, v;
dfn[u] = low[u] = ++dindex;
instack[u] = 1;
q[ed++] = u;
for (i = head[u]; ~i; i = nxt[i])
{
v = ev[i];
if (!dfn[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (instack[v])
{
low[u] = min(low[u], dfn[v]);
}
}
if (dfn[u] == low[u])
{
do{
belong[v = q[--ed]] = bcnt;
instack[v] = 0;
}while (v != u);
bcnt++;
}
}
int main()
{
//freopen("D:/a.txt", "r", stdin);
int n, m;
e = 0;
clr(head, -1);
scanf("%d%d", &n, &m);
for (int i=0; i<m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
addedge(u-1, v-1);
}
ed = bcnt = dindex = 0;
clr(dfn, 0);
clr(cou, 0);
clr(out, false);
clr(instack, 0);
for (int i=0; i<n; i++)
{
if (!dfn[i]) tarjan(i);
}
for (int i=0; i<n; i++)
{
cou[belong[i]]++;
for (int j=head[i]; ~j; j = nxt[j])
{
if (belong[i]!=belong[ev[j]])
{
out[belong[i]] = true;
}
}
}
int number = 0, ans = 0;
for (int i=0; i<bcnt; i++)
{
if (!out[i])
{
number++;
ans = cou[i];
}
}
if (number == 1) printf("%d\n", ans);
else printf("0\n");
return 0;
}