逐个点搜索,毫无疑问超时。
想到把每个强连通分量进行缩点,那么什么样的缩点能让其他所有点到达呢?首先,缩点内部肯定是连通的,不用考虑了。外部的话,将强连通分量缩点后的新图是一个DAG,那答案一定是出度为0的缩点内点的个数。但是出度为0的点只能有一个,多个的话彼此不连通,答案为0。
所以本题为一个tarjan算法变形。
数据结构如下:
const int maxn = 1e4+100;
int n, m, dfn[maxn], low[maxn], cnt, node[maxn], id, vis[maxn], out[maxn];
vector<int> g[maxn];
stack<int> s;
tarjan板子:
void tarjan(int u){
dfn[u] = low[u] = ++cnt;
s.push(u);
vis[u] = 1;
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if(!dfn[v]){
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if(vis[v]) low[u] = min(low[u], dfn[v]);
}
if(low[u] == dfn[u]){
int v;
id++;
do{
v = s.top();
s.pop();
vis[v] = 0;
node[v] = id;
}while(u != v);
}
}
主函数:
int main(){
cin >> n >> m;
int from, to;
for(int i = 0; i < m; i++){
cin >> from >> to;
g[from].push_back(to);
}
for(int i = 1; i <= n; i++)
if(!dfn[i]) tarjan(i);
//求各个缩点出度
for(int u = 1; u <= n; u++){
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if(node[u] != node[v])
out[node[u]]++;
}
}
int count = 0, ans = 0, ID;
for(int i = 1; i <= id; i++){
if(!out[i]){
ID = i;//记录该缩点id
count++;
}
if(count > 1){//超过1个出度为0的缩点,答案为0
cout << 0 << '\n';
return 0;
}
}
//统计出度为0的缩点内的结点数
for(int i = 1; i <= n; i++)
if(node[i] == ID) ans++;
cout << ans << '\n';
return 0;
}