题意:每条信息说明了两个一定不在一个集合里的人,求最少情况集合可以划分为多少子集。
一看就是拓补树的最高层数,但题意中隐含了可能有环(>=关系偏序),所以要先缩点,再拓补。当然,缩点之后图中没有环,直接dfs记忆化也是ok的。
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<map> #include<queue> #include<vector> #include<cstring> #include<algorithm> #define rep(i,a,b) for(int i=(a);i<(b);i++) #define rev(i,a,b) for(int i=(a);i>=(b);i--) #define clr(a,x) memset(a,x,sizeof a) #define INF 0x3f3f3f3f typedef long long LL; using namespace std; const int maxn=100005; const int maxm=300005; int first[maxn],ecnt,u[maxm],v[maxm],nex[maxm]; int low[maxn],dfn[maxn],stck[maxn],belong[maxn]; int indx,top,scc; bool ins[maxn]; int num[maxn]; int in[maxn],out[maxn]; int h[maxn]; int n,m; int ecntt,firstt[maxn],uu[maxm],vv[maxm],nexx[maxm]; void tarjan(int u) { low[u]=dfn[u]=++indx; stck[top++]=u; ins[u]=1; for(int e=first[u];~e;e=nex[e]) { if(!dfn[v[e]]) { tarjan(v[e]); low[u]=min(low[u],low[v[e]]); } else if(ins[v[e]])low[u]=min(low[u],dfn[v[e]]); } if(low[u]==dfn[u]) { int v; scc++; do { v=stck[--top]; ins[v]=false; belong[v]=scc; num[scc]++; }while(v!=u); } } void solve(int n) { clr(dfn,0); clr(ins,0); clr(num,0); indx=scc=top=0; for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); } void add_(int a,int b) { u[ecnt]=a; v[ecnt]=b; nex[ecnt]=first[a]; first[a]=ecnt++; } void add__(int a,int b) { uu[ecntt]=a; vv[ecntt]=b; nexx[ecntt]=firstt[a]; firstt[a]=ecntt++; } void init() { ecnt=0; clr(first,-1); } bool topsort(int n,int first[],int v[],int nex[]) { queue<int>q; memset(h,0,sizeof h); for(int i=1;i<=n;i++) if(!in[i])q.push(i),h[i]=num[i]; int cur=0; while(!q.empty()) { int x=q.front();q.pop(); cur++; for(int e=first[x];~e;e=nex[e]) if(v[e]!=-1){ h[v[e]]=max(h[v[e]],h[x]+num[v[e]]); if(--in[v[e]]==0)q.push(v[e]); } } return cur==n; } int dfs(int root) { if(h[root])return h[root]; h[root]=num[root]; for(int e=firstt[root];~e;e=nexx[e]) { dfs(vv[e]); h[root]=max(h[root],h[vv[e]]+num[root]); } return h[root]; } int gettop(int n) { clr(h,0); int ans=1; for(int i=1;i<=n;i++) if(!in[i]) { ans=max(ans,dfs(i)); } return ans; } void suodian() { ecntt=0;clr(firstt,-1); clr(in,0); for(int e=0;e<ecnt;e++) { int a=belong[u[e]]; int b=belong[v[e]]; if(a!=b)add__(a,b),in[b]++; } } int main() { int a,b; while(~scanf("%d%d",&n,&m)) { init(); for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); add_(a,b); } solve(n); suodian(); topsort(scc,firstt,vv,nexx); int ans=1; for(int i=1;i<=scc;i++) ans=max(ans,h[i]); /*int ans=gettop(scc);*/ printf("%d\n",ans); } return 0; }
时间: 2024-10-10 14:15:29