求双联通分量后简单DP下就行了,白书上的一个题。唉,在dfs_clock应该先++,这里卡死了
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<stack> using namespace std; const int maxn=1500; const int maxm=1e5+100; int e,n,m,head[maxn],nxt[maxm],pnt[maxm]; int dfs_clock,scc_cnt,sccno[maxn],dfn[maxn],lowlink[maxn]; int u[maxm],v[maxm],cnt[maxn],dp[maxn]; bool is[1001][1001]; stack<int> s; void AddEdge(int u,int v) { pnt[e]=v;nxt[e]=head[u];head[u]=e++; } void dfs(int u) { dfn[u]=lowlink[u]=++dfs_clock; s.push(u); for(int i=head[u];i!=-1;i=nxt[i]) { if(!dfn[pnt[i]]) { dfs(pnt[i]); lowlink[u]=min(lowlink[u],lowlink[pnt[i]]); } else if(!sccno[pnt[i]]) { lowlink[u]=min(lowlink[u],dfn[pnt[i]]); } } if(lowlink[u]==dfn[u]) { scc_cnt++; for(;;) { int x=s.top(); s.pop(); sccno[x]=scc_cnt; cnt[scc_cnt]++; if(x==u) break; } } } void find_scc(int n) { dfs_clock=scc_cnt=0; memset(sccno,0,sizeof(sccno)); memset(dfn,0,sizeof(dfn)); memset(cnt,0,sizeof(cnt)); for(int i=1;i<=n;i++) if(!dfn[i]) dfs(i); } int DP(int u) { if(dp[u]) return dp[u]; dp[u]=cnt[u]; for(int i=head[u];i!=-1;i=nxt[i]) dp[u]=max(dp[u],DP(pnt[i])+cnt[u]); return dp[u]; } void rebuild() { e=0; memset(is,0,sizeof(is)); memset(head,-1,sizeof(head)); memset(dp,0,sizeof(dp)); for(int i=0;i<m;i++) if(sccno[u[i]]!=sccno[v[i]]&&!is[sccno[u[i]]][sccno[v[i]]]) { is[sccno[u[i]]][sccno[v[i]]]=1; AddEdge(sccno[u[i]],sccno[v[i]]); } int ans=0; for(int i=1;i<=scc_cnt;i++) { ans=max(ans,DP(i)); // printf("SSSS %d %d\n",i,cnt[i]); } printf("%d\n",ans); } int main() { int T; scanf("%d",&T); while(T--) { e=0; scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); for(int i=0;i<m;i++) { scanf("%d%d",&u[i],&v[i]); AddEdge(u[i],v[i]); } find_scc(n); rebuild(); } return 0; }