题目大意:求一张有向图中的点数大于1的强连通分量个数,并从小到大按顺序输出输出可能存在的与其它强连通分量都相同的强连通分量的组成端点。
思路:对第一问直接tarjan即可。对第二问我用的dfs,但实际上如果存在,这是缩点后内向树(就是儿子节点指向根节点的有向树)的根节点,再判断出度为0的点是否唯一即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
#include<set>
using namespace std;
const int maxn=1005;
int n,m,tot=0,dex=0,ans=0;
vector<int> g[maxn]/*,rg[maxn]*/,ng[maxn];
set<int> scc[maxn];
stack<int> s;
int dfn[maxn],low[maxn],belong[maxn];
bool in[maxn];
void init()
{
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(belong,0,sizeof(belong));
memset(in,0,sizeof(in));
scanf("%d%d",&n,&m);
while (m--)
{
int a,b;
scanf("%d%d",&a,&b);
g[b].push_back(a);
}
}
void tarjan(int u)
{
dfn[u]=low[u]=++dex;
s.push(u);
in[u]=1;
for (int i=0;i<g[u].size();++i)
{
if (!dfn[g[u][i]])
{
tarjan(g[u][i]);
low[u]=min(low[u],low[g[u][i]]);
}
else
{
if (in[g[u][i]])
{
low[u]=min(low[u],dfn[g[u][i]]);
}
}
}
if (dfn[u]==low[u])
{
tot++;
int now=-1;
int cnt=0;
while (now!=u)
{
now=s.top();
cnt++;
in[now]=0;
s.pop();
belong[now]=tot;
scc[tot].insert(now);
}
if (cnt>1)
ans++;
}
}
void rebuild()
{
for (int i=1;i<=n;++i)
for (int j=0;j<g[i].size();++j)
{
if (belong[i]!=belong[g[i][j]])
{
ng[belong[i]].push_back(belong[g[i][j]]);
}
}
}
int cnt=0;
bool vis[maxn];
void dfs(int u)
{
for (int i=0;i<ng[u].size();++i)
if (!vis[ng[u][i]])
{
vis[ng[u][i]]=1;
cnt++;
dfs(ng[u][i]);
}
}
void work()
{
printf("%d\n",ans);
for (int i=1;i<=tot;++i)
{
memset(vis,0,sizeof(vis));
cnt=0;
vis[i]=1;
dfs(i);
if (cnt==tot-1 && cnt!=0 && scc[i].size()!=1)
{
set<int>::iterator it;
for (it=scc[i].begin();it!=scc[i].end();++it)
printf("%d ",(*it));
return;
}
}
if (tot==1 && scc[tot].size()!=1)
{
set<int>::iterator it;
for (it=scc[tot].begin();it!=scc[tot].end();++it)
printf("%d ",(*it));
return;
}
puts("-1");
}
int main()
{
init();
for (int i=1;i<=n;++i)
if (!dfn[i])
tarjan(i);
rebuild();
work();
return 0;
}