洛谷题单指南-连通性问题-P2341 [USACO03FALL / HAOI2006] 受欢迎的牛 G
原题链接:https://www.luogu.com.cn/problem/P2341
题意解读:把奶牛看作图中节点,奶牛的喜欢关系看作有向边,求有多少节点可以被所有节点走到。
解题思路:
如果是一个DAG,问题就好办了,能被所有节点走到的节点就是出度为0的那个节点,如果有多个出度为0的节点,则不能互相走到。
但是不是DAG,就要想办法变成DAG,通过对强联通分量缩点,即可得到DAG。
判断出度为0的缩点个数,大于1则答案为0,否则输出出度为0的缩点中节点的个数,即为答案。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 10005, M = 50005;
int head[N], to[M], nxt[M], idx;
int dfn[N], low[N], timestamp;
stack<int> stk;
bool vis[N];
int cnt;
int scc[N], sz[N], out[N];
int n, m;
void add(int a, int b)
{
to[++idx] = b;
nxt[idx] = head[a];
head[a] = idx;
}
void tarjan(int u)
{
dfn[u] = low[u] = ++timestamp;
stk.push(u);
vis[u] = true;
for(int i = head[u]; i; i = nxt[i])
{
int v = to[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(dfn[u] == low[u])
{
cnt++;
while(true)
{
int v = stk.top();
stk.pop();
vis[v] = false;
scc[v] = cnt;
sz[cnt]++;
if(v == u) break;
}
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
int u, v;
cin >> u >> v;
add(u, v);
}
for(int i = 1; i <= n; i++)
if(!dfn[i])
tarjan(i);
//统计每个强连通分量的出度
for(int u = 1; u <= n; u++)
{
for(int j = head[u]; j; j = nxt[j])
{
int v = to[j];
if(scc[u] != scc[v]) out[scc[u]]++;
}
}
int ans = 0, sum = 0;
for(int i = 1; i <= cnt; i++)
{
if(out[i] == 0) sum++, ans += sz[i];
}
if(sum > 1) cout << 0 << endl;
else cout << ans << endl;
return 0;
}