P2835 刻录光盘
题解
好抽象啊!!!
大概思路就是把强连通分量看作一个点,然后在此基础上找入度为零的点
code
#include<bits/stdc++.h>
using namespace std;
vector<int> G[205];
int in[205]={0};//代表强连通分量的入度
int belong[205]={0};//代表每个点属于哪个强连通分量
int len=0,cnt=0;//len代表时间戳,cnt代表强连通分量的个数
int vis[205]={0};//代表时间戳
int low[205]={0};//代表这个强连通分量内的点能到达的最小时间戳
stack<int> q;//栈的作用是,将同一强连通分量的点进行归类
int along[205]={0};
void ss(int now)
{
vis[now]=++len;
low[now]=vis[now];
q.push(now);
along[now]=1;//数组along的作用是判断点是否是同一轮遍历的,不然时间戳小的点做了非同一强连通分量的子节点使父节点low值错误更新
for(auto next:G[now])
{
if(!vis[next])
{
ss(next);
low[now]=min(low[now],low[next]);
}
else if(along[next])
{
low[now]=min(low[now],vis[next]);
}
}
if(low[now]==vis[now])
{
++cnt;
int x;
do
{
x=q.top();
q.pop();
along[x]=0;
belong[x]=cnt;
}while(x!=now);
}
}
int main()
{
int n,x;
cin>>n;
for(int i=1;i<=n;i++)
while(cin>>x&&x!=0) G[i].push_back(x);
for(int i=1;i<=n;i++)
if(!vis[i]) ss(i);
for(int i=1;i<=n;i++)
for(auto next:G[i])
if(belong[i]!=belong[next]) in[belong[next]]++;
int ans=0;
for(int i=1;i<=cnt;i++) ans+=(!in[i]);
cout<<ans<<endl;
return 0;
}

浙公网安备 33010602011771号