题目链接
思路
- 先跑一遍tarjan求出所有强连通分量,并缩点(即把多于一个点的缩成一个点)
- 要是最终的那个有向图中只有一个点出度为零且它为一个“爱心天使”(即它所代表的分量有两个或以上个点),则输出它所包含的编号。
- 注意:要是最终的图中有多个点出度为零,那么说明多于一个点是没爱任何人的,那么就肯定没有一个点是被其它所有点所爱的。
程序
由于数据小,直接用邻接数组来记录了
#include <cstdio>
int n,m,time,f[2000][2000];
int low[2000],dfn[2000];
int st[2000],_st[2000],top;
int fa[2000],ff[2000][2000],num,anum;
int duru;
int du(){scanf("%d",&duru); return duru;}
void tarjan(int p){
low[p]=dfn[p]=++time;
_st[p]=st[++top]=p;
for (int q=1; q<=n; q++) if (f[p][q]){
if (!_st[q] && !fa[q]){
tarjan(q);
if (low[q]<low[p]) low[p]=low[q];
}
else if (_st[q] && dfn[q]<low[p]) low[p]=dfn[q];
}
if (low[p]==dfn[p]){
int kkk=1;
fa[st[top]]=++num,_st[st[top]]=0;
while (st[top--]!=p) fa[st[top]]=num,_st[st[top]]=0,kkk++;
if (kkk>1) anum++;
}
}
void check(){
int boo[2000],ans[2000],ansn,fff=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) if (f[i][j] && fa[i]!=fa[j]) boo[fa[i]]=1;
for (int i=1; i<=num; i++) if (!boo[i]){
ansn=0;
for (int j=1; j<=n; j++) if (fa[j]==i) ans[++ansn]=j;
if (ansn>1){
if (!fff) fff=1;
else fff=0;
}
}
if (!fff) printf("-1");
else for (int i=1; i<=ansn; i++) printf("%d ",ans[i]);
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1; i<=m; i++) f[du()][du()]=1;
for (int i=1; i<=n; i++) if (!fa[i]) tarjan(i);
printf("%d\n",anum);
check();
}