链接:
https://www.nowcoder.com/acm/contest/81/C
来源:牛客网
来源:牛客网
题目描述
给出一个 0 ≤ N ≤ 10
5 点数、0 ≤ M ≤ 10
5 边数的有向图,
输出一个尽可能小的点集,使得从这些点出发能够到达任意一点,如果有多个这样的集合,输出这些集合升序排序后字典序最小的。
输出一个尽可能小的点集,使得从这些点出发能够到达任意一点,如果有多个这样的集合,输出这些集合升序排序后字典序最小的。
输入描述:
第一行为两个整数 1 ≤ n, m ≤ 105, 接下来 M 行,每行两个整数 1 ≤ u, v ≤ 105 表示从点 u 至点 v 有一条有向边。 数据保证没有重边、自环。
输出描述:
第一行输出一个整数 z,表示作为答案的点集的大小; 第二行输出 z 个整数,升序排序,表示作为答案的点集。
示例1
输入
7 10 4 5 5 1 2 5 6 5 7 2 4 2 1 2 5 3 3 5 3 6
输出
2 4 7
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int ne[N],p[N],h[N],j,dfn[N],cnt,b[N],t,s[N],M,a[N],low[N],f[N],in[N],ans[N],A;
int n,m;
void dfs(int x){
dfn[x]=low[x]=++cnt;
b[x]=1;
s[++t]=x;
int i;
for(i=h[x];i;i=ne[i]){
if(!dfn[p[i]]){
dfs(p[i]);
low[x]=min(low[x],low[p[i]]);
}else if(b[p[i]]){
low[x]=min(low[x],dfn[p[i]]);
}
}
if(dfn[x]==low[x]){
M++;
a[M]=n;
do{
i=s[t--];
f[i]=M;
b[i]=0;
a[M]=min(a[M],i);
}while(i!=x);
}
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
//freopen("in.txt","r",stdin);
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>j>>p[i];
ne[i]=h[j];
h[j]=i;
}
for(int i=1;i<=n;i++)if(!dfn[i])dfs(i);
for(int i=1;i<=n;i++)for(j=h[i];j;j=ne[j])
if(f[p[j]]!=f[i])in[f[p[j]]]++;
for(int i=1;i<=M;i++)if(!in[i])ans[++A]=a[i];
sort(ans+1,ans+1+A);
cout<<A<<endl;
int i;
for(i=1;i<A;i++)
cout<<ans[i]<<" ";
cout<<ans[i];
return 0;
}