题目:http://acm.hust.edu.cn/vjudge/problem/16578
抽象出来的题意:给定一个有向图,求有多少个顶点是由任何顶点出发都可达的。
题解:
1、有向无环图中唯一出度为0的点,一定可以由任何点出发均可达。
2、则现在的要求就变成了把图构造成有向无环图DAG,并计算无环图中每个点的出度。
若要构建有向无环图,就要把所有的环都缩成一个点,当把所有的环都缩成一个点以后,有向无环图就出现了。
3、那要如何找到所有的环呢。我们可以来看一下强连通的定义:图论中,强连通图指每一个顶点皆可以经由该图上的边抵达其他的每一个点的有向图。那对图求一下强连通分量(可以参考满天飞的模板,我这里用的是kuangbin的Korasaju算法模板),每一个强连通分量不就是一个环么,把所有强连通分量缩成一个环,DAG就出现了。
4、如何缩点。开一个Belong数组,把所有属于同一个强连通分量的点标记成一个数字,这样就类似于缩点了。
5、计算出度方法
int de[maxn];
memset (de, 0, sizeof(de));
for (int i = 1; i <= m; i++) {
if (Belong[e[i].l] != Belong[e[i].r]) {
de[Belong[e[i].l]]++;
}
}
思考:
1、有向无环图中唯一出度为0的点,一定可以由任何点出发均可达
2、因为要构造有向无环图DAG,则把每个强连通分量缩成一点
3、缩点的时候不一定要构造新图,只要把不同强连通分量的点染不同颜色,然后考察各种颜色的点有没有连到别的颜色的边即可
#include <iostream>
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
using namespace std;
const int maxm = 50010;
const int maxn = 10010;
struct Edge{
int l, r;
}e[maxm];
struct Node{
int to, next;
}edge1[maxm], edge2[maxm];
int head1[maxn], head2[maxn];
bool mark1[maxn], mark2[maxn];
int tot1, tot2;
int cnt1, cnt2;
int st[maxn];
int Belong[maxn];
int num;
int SetNum[maxn];
void addedge(int u, int v)
{
edge1[tot1].to = v;
edge1[tot1].next = head1[u];
head1[u] = tot1++;
edge2[tot2].to = u;
edge2[tot2].next = head2[v];
head2[v] = tot2++;
}
void DFS1(int u)
{
mark1[u] = true;
for (int i = head1[u]; i != -1 ;i = edge1[i].next) {
if (!mark1[edge1[i].to]) DFS1( (edge1[i].to));
}
st[cnt1++] = u;
}
void DFS2(int u)
{
mark2[u] = true;
num++;
Belong[u] = cnt2;
for (int i = head2[u]; i != -1; i = edge2[i].next)
if (!mark2[edge2[i].to]) DFS2 (edge2[i].to);
}
void solve(int n)
{
memset (mark1 ,false, sizeof(mark1));
memset (mark2, false, sizeof(mark2));
cnt1 = cnt2 = 1;
for (int i = 1; i <= n; i++) {
if (!mark1[i]) DFS1 (i);
}
for (int i = cnt1 - 1; i >= 1; i--) {
if (!mark2[st[i]]) {
num = 0;
DFS2 (st[i]);
SetNum[cnt2++] = num;
}
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen ("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
int n, m;
scanf ("%d%d", &n, &m);
tot1 = tot2 = 1;
for(int i = 1; i <= n; i++)//初始化
{
head1[i] = head2[i] = -1;
mark1[i] = mark2[i] = 0;
}
for (int i = 1; i <= m; i++) {
int a, b;
scanf ("%d%d", &a, &b);
e[i].l = a;
e[i].r = b;
addedge (a, b);
}
solve (n);
//计算出度
int de[maxn];
memset (de, 0, sizeof(de));
for (int i = 1; i <= m; i++) {
if (Belong[e[i].l] != Belong[e[i].r]) {
de[Belong[e[i].l]]++;
}
}
int cnt = 0, res;
for (int i = 1; i < cnt2; i++) {
if (!de[i]) {
cnt++;
res = i;
}
}
if (cnt > 1) printf ("0\n");
else printf ("%d\n", SetNum[res]);
return 0;
}