洛谷P3436
直接说解法。
首先可以发现,如果图中出现环,就会出现无数条路径,因为我们可以在环里走无数圈来增加路径数量。
所以我们可以缩点处理环,顺便处理环上点的个数。
然后对于非环上的点,可以在重建图后用拓扑排序简单 DP 来统计每个点到终点的路径总数。特别的,为了方便统计,我们可以把路径总数超出范围的点(包括环上的点)直接赋值为 \(36500\)。
然后统计输出,就做完了。
void add(int fr,int to){
e[++tot]=(edge){fr,to,head[fr]};
head[fr]=tot;
}
void Add(int fr,int to){
E[++TOT]=(edge){fr,to,Head[fr]};
Head[fr]=TOT;
}
void tarjan(int u){
dfn[u]=low[u]=++cnt;
vis[u]=1;zhan[++top]=u;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
if(!dfn[to]) tarjan(to),low[u]=min(low[u],low[to]);
else if(vis[to]) low[u]=min(low[u],dfn[to]);
}
if(dfn[u]==low[u]){
++siz[++t];
int pre=zhan[top--];
num[pre]=t;vis[pre]=0;
while(pre!=u){
++siz[t];
pre=zhan[top--];
num[pre]=t;vis[pre]=0;
}
}
}
void topsort(){
queue<int> q;
for(int i=1;i<=t;i++)
if(!du[i]) q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=Head[u];i;i=E[i].nxt){
int to=E[i].to;
if(--du[to]==0) q.push(to);
if(flag[u]) flag[to]=1;dp[to]+=dp[u];
if(siz[to]>1&&flag[to]) dp[to]=UP;
if(dp[to]>UP) dp[to]=UP;
}
}
}
signed main(){
n=read();m=read();
for(int i=1;i<=m;i++){
fr[i]=read(),to[i]=read();
add(to[i],fr[i]);
}
for(int i=1;i<=n+1;i++) if(!dfn[i]) tarjan(i);
for(int i=1;i<=m;i++){
if(fr[i]==to[i]) ++siz[num[fr[i]]];
else if(num[fr[i]]!=num[to[i]])
Add(num[to[i]],num[fr[i]]),du[num[fr[i]]]++;
}
flag[num[n+1]]=1;
dp[num[n+1]]=1;topsort();
for(int i=1;i<=n;i++){
if(!flag[num[i]]) continue;
ans=max(ans,dp[num[i]]);
}
for(int i=1;i<=n;i++){
if(!flag[num[i]]) continue;
all+=(dp[num[i]]==ans);
}
if(ans==UP) puts("zawsze");
else printf("%d\n",ans);printf("%d\n",all);
for(int i=1;i<=n;i++){
if(!flag[num[i]]) continue;
if(dp[num[i]]==ans) printf("%d ",i);
}
return 0;
}