極大團。即求一個最大點集,使得點集中的任意兩個點u,v至少存在u->v,或者v->u的路徑。
是這樣做的,求出所有的聯通分量,然后整個圖就變成了無環圖,把原來若干個點縮點,點權為分量的點數。這樣相當於找一條權值最大的路徑,因為無環了,所以這個可以通過先拓撲排序然后dp解決。
這里重點說一下自己遇到的坑吧。
d[cur]=low[cur]=++dfsclock; 絕不能是 d[cur]=low[cur]=d[fa]+1;
后者是錯的。
我思考了好久后來才發現問題。如圖:
假設我們按照d[fa]+1的方法來打標記,那么當路徑為1->2->3時候,遞歸返回的時候low[1]=1,low[2]=1,low[3]=2,而此時去訪問4點,此時low[4]最少也只能是2,那么從程序的角度來說,也就認為了4是單獨的強聯通分量,這是不對的。
但是如果我們按照++dfsclock的方法來打標記,那么low[1]=1,low[2]=1,low[3]=2,low[4]=2,但是此時d[4]=4,可以判斷出不是一個單獨的強連通分量。主要是通過++dfsclock可以判斷是否以前被訪問過,這里與源點距離無關,特別注意了。
召喚代碼君:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define maxn 1010 #define maxm 202000 using namespace std; int first[maxn],next[maxm],to[maxm],edge; int low[maxn],d[maxn],belong[maxn],scc; int U[maxm],V[maxm],stack[maxn],top; int f[maxn],sum[maxn],Q[maxn]; int n,m,T,ans,dfsclock; bool cmp(int q1,int q2) { return d[q1]>d[q2]; } void _init() { dfsclock=ans=top=scc=0,edge=-1; for (int i=1; i<=n; i++) first[i]=-1,low[i]=d[i]=belong[i]=0; } void addedge(int uu,int vv) { edge++; to[edge]=vv,next[edge]=first[uu],first[uu]=edge; } void dfs(int cur,int fa) { d[cur]=low[cur]=++dfsclock; stack[++top]=cur; for (int i=first[cur]; i!=-1; i=next[i]) { if (belong[to[i]]) continue; if (!d[to[i]]) dfs(to[i],cur); low[cur]=min(low[cur],low[to[i]]); } if (low[cur]>=d[cur]) for (scc++,f[scc]=0;;) { belong[stack[top--]]=scc; f[scc]++; if (stack[top+1]==cur) break; } } int get(int x) { if (d[x]!=0) return d[x]; if (first[x]==-1) return d[x]=1; d[x]=0; for (int i=first[x]; i!=-1; i=next[i]) d[x]=max(d[x],get(to[i])+1); return d[x]; } int main() { scanf("%d",&T); while (T--) { scanf("%d%d",&n,&m); _init(); for (int i=1; i<=m; i++) { scanf("%d%d",&U[i],&V[i]); addedge(U[i],V[i]); } for (int i=1; i<=n; i++) if (!d[i]) dfs(i,0); edge=-1; for (int i=1; i<=scc; i++) first[i]=-1,d[i]=0; for (int i=1; i<=m; i++) if (belong[U[i]]!=belong[V[i]]) addedge(belong[U[i]],belong[V[i]]); for (int i=1; i<=scc; i++) { Q[i]=i,sum[i]=0; if (!d[i]) d[i]=get(i); } sort(Q+1,Q+1+scc,cmp); for (int i=1; i<=scc; i++) { sum[Q[i]]+=f[Q[i]]; ans=max(ans,sum[Q[i]]); for (int j=first[Q[i]]; j!=-1; j=next[j]) sum[to[j]]=max(sum[to[j]],sum[Q[i]]); } printf("%d\n",ans); } return 0; }