题意:
就是给你一个有向图,没有自环和重边,现在定义一个点如果可以从这里出发然后无穷尽的走下去,那么就是好点,问你有多少好点。
思考:
所谓的好点就是可以走到环里面去,所以就是找环了,如果染色找的话不太好操作,发现这里是有向图,又是环,很快想到了缩点,把环缩一块,然后哪些可以走到这些缩点的也是好点,那么现在就是如何把所有的好点找出来。先判断有环的缩点,就是这个缩点的个数>=2,所以再建立一次边,跑一次反向dp,也就是当前如果为好点,那么他走到的点也是号点,即可。
代码:
int T,n,m,k;
int va[N];
int dfn[N],low[N],vis[N],deep;
int cnt[N],col[N],sum;
int in[N],can[N];
stack<int > s;
vector<int > e[N],v[N];
void dfs(int now)
{
dfn[now] = low[now] = ++deep;
s.push(now);
vis[now] = 1;
for(auto spot:e[now])
{
if(dfn[spot]==0)
{
dfs(spot);
low[now] = min(low[now],low[spot]);
}
else if(vis[spot]) low[now] = min(low[now],dfn[spot]);
}
if(dfn[now]==low[now])
{
col[now] = ++sum;
while(1)
{
int x = s.top();
s.pop();
vis[x] = 0;
col[x] = sum;
cnt[sum]++;
if(x==now) break;
}
}
}
void topsort()
{
queue<int > q;
for(int i=1;i<=sum;i++)
{
if(cnt[i]>=2) can[i] = 1;
if(!in[i]) q.push(i);
}
while(q.size())
{
auto now = q.front();
q.pop();
for(auto spot:v[now])
{
can[spot] |= can[now];
if(--in[spot]==0) q.push(spot);
}
}
}
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
e[a].pb(b);
}
for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i);
for(int i=1;i<=n;i++)
{
for(auto j:e[i])
{
if(col[i]!=col[j])
{
v[col[j]].pb(col[i]);
in[col[i]]++;
}
}
}
topsort();
int anw = 0;
for(int i=1;i<=sum;i++) if(can[i]) anw += cnt[i];
cout<<anw;
return 0;
}
总结:
多多思考。