n个顶点,m条边的有向图G,求最大团。
显然对于一个SCC,其中的点要么全部包含在最大团中,要么均不在最大团里。
因此可以先通过求出SCC,然后缩点得到DAG图,每一个点的权值为对应的SCC中点的个数。
再用动态规划求解。设dp[x]表示从点x出发所能获得的最大权值,则dp[x]=max(dp[x],dp[v]+cnt[x]),v为与x相关联的边,cnt[x]为x对应的SCC点个数
#include<bits/stdc++.h> using namespace std; #define maxn 1005 vector<int> G[maxn]; int pre[maxn],low[maxn],sccno[maxn],dfs_clock,scc_cnt; stack<int> S; int cnt[maxn],fa[maxn]; void dfs(int u){ pre[u]=low[u]=++dfs_clock; S.push(u); for(int i=0;i<G[u].size();++i){ int v=G[u][i]; if(!pre[v]){ dfs(v); low[u]=min(low[u],low[v]);//用后代的low函数更新自身 } else if(!sccno[v]){ low[u]=min(low[u],pre[v]);//用反向边更新 } } if(low[u]==pre[u]){ cnt[++scc_cnt]=0; 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(pre,0,sizeof(pre)); for(int i=0;i<n;++i) if(!pre[i]) dfs(i); } int dp[maxn]; vector<int> G1[maxn]; int getdp(int x){ if(dp[x]) return dp[x]; dp[x]=cnt[x]; for(int i=0;i<G1[x].size();++i) { int v=G1[x][i]; dp[x]=max(dp[x],getdp(v)+cnt[x]); } return dp[x]; } int main() { int i,t,a,b,j,n,m; cin>>t; while(t--) { scanf("%d%d",&n,&m); for(i=0;i<=n;++i) {G[i].clear();G1[i].clear();} for(i=1;i<=m;++i){ scanf("%d%d",&a,&b); --a,--b; G[a].push_back(b); } find_scc(n); for(i=0;i<n;++i){ for(j=0;j<G[i].size();++j) { int v=G[i][j]; if(sccno[v]!=sccno[i]){ G1[sccno[i]].push_back(sccno[v]); } } } memset(dp,0,sizeof(dp)); int ans=0; for(i=1;i<=scc_cnt;++i) ans=max(getdp(i),ans); printf("%d\n",ans); } return 0; }