题意:
给定一个有向图,求有多少个顶点是由任何一个顶点出发都可达的。
思路:
定理:DAG中唯一出度为0的点,一定可以由任何点出发均可达(由于无环,所以从任何点出发往前走,必然终止于一个出度为0的点)。
另外,答案为0的情况有两种:一为底图不连通,二为有不止一个出度有0的缩点。
大致流程:
1、DFS一遍查底图是否连通;
2、Tarjan算法求所有SCC并缩点;
3、再DFS一遍新图(缩点之后的图)求每个缩点的出度。
注意:
缩点的时候不一定要构造新图,只要把不同强连通分量的点染不同颜色,然后考察各种颜色的点有没有连到别的颜色的边即可(即其对应的缩点后的DAG图上的点是否有出边)。
反思:
1、提交前一定要查看是否把一些自己加的输出给注释掉了!
2、诸如inStack数组可以改为int型的数组来记录更多的信息,
如 0:未进过栈 1:在栈中 2:曾在栈中
代码:
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 10000 + 10;
vector<int> graph[MAXN];
vector<int> graph1[MAXN];//有向图的底图,用于检验是否连通
int inStack[MAXN];//0:未进过栈 1:在栈中 2:曾在栈中
int st[MAXN], low[MAXN], dfn[MAXN];
int top, cnt, num;//cnt:顶点数量 num:scc数量
int amt[MAXN];//用于记录每个scc中的顶点个数
int belong[MAXN];//每个顶点从属于哪个lcc
int n, m;
int cnt1;//底图一次遍历到的顶点个数
bool vis[MAXN];
bool vis1[MAXN];
int outdegree[MAXN];//统计每个缩点的出度
void tarjan(int u)
{
dfn[u] = low[u] = ++cnt;
st[top++] = u;
inStack[u] = 1;
for(int i = 0; i < graph[u].size(); i++)
{
int v = graph[u][i];
if(inStack[v] == 1)
{
low[u] = min(low[u], dfn[v]);
}
if(!inStack[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
}
if(dfn[u] == low[u])
{
++num;
int x;
do
{
x = st[--top];
inStack[x] = 2;
belong[x] = num;
amt[num]++;
}
while(x != u);
}
return;
}
void init()
{
for(int i = 0; i <= n; i++)
{
graph[i].clear();
graph1[i].clear();
}
memset(inStack, 0, sizeof(inStack));
memset(amt, 0, sizeof(amt));
memset(belong, 0, sizeof(belong));
memset(vis, false, sizeof(vis));
memset(vis1, false, sizeof(vis1));
memset(outdegree, 0, sizeof(outdegree));
top = cnt = num = 0;
cnt1 = 0;
}
void dfs(int u)
{
cnt1++;
vis[u] = true;
for(int i = 0; i < graph1[u].size(); i++)
{
int v = graph1[u][i];
if(!vis[v]) dfs(v);
}
}
void dfs1(int u)//统计每个缩点的出度
{
vis1[u] = true;
for(int i = 0; i < graph[u].size(); i++)
{
int v = graph[u][i];
if(belong[u] != belong[v])
{
outdegree[belong[u]]++;
}
if(!vis1[v])
{
dfs1(v);
}
}
}
int main()
{
while(~scanf("%d%d", &n, &m))
{
init();
for(int i = 0; i < m; i++)
{
int u, v;
scanf("%d%d", &u, &v);
graph[u].push_back(v);
graph1[u].push_back(v);
graph1[v].push_back(u);
}
dfs(1);
if(cnt1 != n)
{
printf("0\n");
continue;
}
for(int i = 1; i <= n; i++)
{
if(!inStack[i])
{
tarjan(i);
}
}
for(int i = 1; i <= n; i++)
{
if(!vis1[i])
{
dfs1(i);
}
}
int sum = 0, pos;
for(int i = 1; i <= num; i++)
{
if(outdegree[i] == 0) sum++, pos = i;
}
if(sum == 1)
{
printf("%d\n", amt[pos]);
}
else printf("0\n");
}
return 0;
}