对于一条边x->y,若去掉之后x不能到达y,那么它是必需的。
首先拓扑排序求出拓扑序,然后按照终点拓扑序为第一关键字,起点拓扑序为第二关键字从小到大加边。
对于每个点,维护一个bitset,表示当前从哪些点可以到达自己。
时间复杂度$O(frac{nm}{32})$。
#include<cstdio> #include<bitset> #include<algorithm> using namespace std; typedef pair<int,int>P; const int N=1502,M=10002; int n,m,i,j,x,y,d[N],g[N],g2[N],v[M],v2[M],nxt[M],nxt2[M],ed,h,t,q[N],ans;bitset<N>f[N];P b[M]; inline void add(int x,int y){d[y]++;v[++ed]=y;nxt[ed]=g[x];g[x]=ed;} inline void add2(int x,int y){v2[++ed]=y;nxt2[ed]=g2[x];g2[x]=ed;} int main(){ scanf("%d%d",&n,&m); for(i=1;i<=n;i++)f[i][i]=1; while(m--)scanf("%d%d",&x,&y),add(x,y); for(ed=0,i=h=1;i<=n;i++)if(!d[i])q[++t]=i; while(h<=t)for(i=g[x=q[h++]];i;add2(v[i],x),i=nxt[i])if(!(--d[v[i]]))q[++t]=v[i]; for(i=1;i<=n;i++)for(j=g2[x=q[i]];j;f[x]|=f[v2[j]],j=nxt2[j])if(!f[x][v2[j]])b[++ans]=P(v2[j],x); sort(b+1,b+ans+1); for(printf("%d ",ans),i=1;i<=ans;i++)printf("%d %d ",b[i].first,b[i].second); return 0; }