传送门
首先将便反向,这样就变成了从主楼到其他楼的路径数
然后我们大力tarjan求强连通分量。
发现一个强连通分量内又多于2个点显然是GG的。
其他随便拓扑排序就可以了。
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 1001001
#define inf 36501
using namespace std;
int n,m,tot,top,cnt,sum,ans,x,y,h,t,to;
int dfn[N],head[N],low[N],co[N];
int du[N],sz[N],f[N],q[N];
bool in[N],vis[N];
vector<int> vec[N];
struct edge{int to,next;}e[N];
void add(int x,int y){
e[++tot]=(edge){y,head[x]};
head[x]=tot;
}
void tarjan(int x){
dfn[x]=low[x]=++cnt;
q[++top]=x; in[x]=1;
for (int i=head[x];i;i=e[i].next)
if (!dfn[e[i].to]){
tarjan(e[i].to);
low[x]=min(low[x],low[e[i].to]);
}
else if (in[e[i].to])
low[x]=min(low[x],dfn[e[i].to]);
if (dfn[x]==low[x]){
int tmp=q[top--];
in[tmp]=0; co[tmp]=++sum;
while (tmp!=x){
tmp=q[top--];
in[tmp]=0; co[tmp]=sum;
}
}
}
int main(){
scanf("%d%d",&n,&m); n++;
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
add(y,x);
if (x==y) vis[x]=1;
}
for (int i=1;i<=n;i++)
if (!dfn[i]) tarjan(i);
for (int i=1;i<=n;i++) sz[co[i]]++;
for (int i=1;i<=n;i++)
for (int j=head[i];j;j=e[j].next)
if (co[i]!=co[e[j].to]){
vec[co[i]].push_back(co[e[j].to]);
du[co[e[j].to]]++;
}
for (int i=1;i<=n;i++)
if (vis[i]) sz[co[i]]++;
for (int i=1;i<=n;i++)
if (!du[i]) q[++t]=i;
f[co[n]]=1;
if (sz[co[n]]>1) f[co[n]]=inf;
while (h!=t){
x=q[++h];
for (int i=0;i<vec[x].size();i++){
to=vec[x][i];
f[to]+=f[x];
if (f[to]>inf||(sz[to]>1&&f[to])) f[to]=inf;
du[to]--;
if (!du[to]) q[++t]=to;
}
}
for (int i=1;i<n;i++)
ans=max(ans,f[co[i]]);
if (ans!=inf) printf("%d\n",ans);
else puts("zawsze");
for (int i=1;i<n;i++)
if (f[co[i]]==ans) q[++top]=i;
printf("%d\n",top);
for (int i=1;i<=top;i++)
printf("%d ",q[i]);
}