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;
}