题意:给你一张有向图,求一个节点数最大的节点集,使得该节点集中任意两个节点u,v。满足:要么u可达v,要么v可达u,要么互达。
思路:重新构造图,求出图中的所有scc,把同一个scc看做一个点,这样得到一张新的DAG,然后用拓扑排序求出DAG最长路即为答案。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn = 2020;
int pre[maxn],low[maxn],scc[maxn],sz[maxn],d[maxn],dp[maxn];
int dfs_clock,scc_cnt;
vector<int>G[maxn],G1[maxn];
stack<int>s;
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[v],low[u]);
}else if(!scc[v])low[u] = min(low[u],pre[v]);
}
if(low[u] == pre[u])
{
++scc_cnt;
while(1)
{
int x = s.top();
s.pop();
scc[x] = scc_cnt;
sz[scc_cnt]++;
if(x == u)break;
}
}
}
void find_scc(int n)
{
dfs_clock = scc_cnt = 0;
memset(pre,0,sizeof(pre));
memset(sz,0,sizeof(sz));
memset(scc,0,sizeof(scc));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
if(!pre[i])dfs(i);
}
void topsort()
{
queue<int>q;
for(int i=1;i<=scc_cnt;i++)dp[i] = sz[i];
for(int i=1;i<=scc_cnt;i++)if(!d[i])q.push(i);
while(!q.empty())
{
int u = q.front();
q.pop();
for(int i=0;i<G1[u].size();i++)
{
int v = G1[u][i];
dp[v] = max(dp[u] + sz[v],dp[v]);
if(--d[v] == 0)q.push(v);
}
}
int ans = *max_element(dp+1,dp+1+scc_cnt);
printf("%d\n",ans);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n+5;i++)G[i].clear(),G1[i].clear();
memset(d,0,sizeof(d));
for(int i=0;i<m;i++)
{
int u,v;
scanf("%d%d",&u,&v);
G[u].pb(v);
}
find_scc(n);
for(int u = 1;u<=n;u++)
for(int i=0;i<G[u].size();i++)
{
int v = G[u][i];
if(scc[v] == scc[u])continue;
G1[scc[u]].pb(scc[v]);
d[scc[v]]++;
}
topsort();
}
}
来源:CSDN
作者:OerUUU
链接:https://blog.csdn.net/weixin_44499508/article/details/104374370