有一张有向图G 求一个节点数最大的节点集 其中任意2点 u和v 要么u 可以到v 要么v可以到u 要么相互可达
首先缩点 每一个强连通分量都是可达的 求一条路径 路径上的每个点的权值是该强连通分量的节点数 求权最大的路径 可以用记忆化搜索写
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
using namespace std;
const int maxn = 1010;
vector <int> G[maxn];
stack <int> s;
int pre[maxn];
int low[maxn];
int cnt[maxn];
int degree[maxn];
int sccno[maxn];//每个点所在强联通分量的scc_cnt
int dfs_clock;
int scc_cnt;
int n, m;
vector <int> a[maxn];
int d[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]);
}
else if(!sccno[v])
{
low[u] = min(low[u], pre[v]);
}
}
if(low[u] == pre[u])
{
scc_cnt++;
while(1)
{
int x = s.top();
s.pop();
sccno[x] = scc_cnt;
cnt[scc_cnt]++;
if(x == u)
break;
}
}
}
void find_scc()
{
dfs_clock = scc_cnt = 0;
memset(sccno, 0, sizeof(sccno));
memset(pre, 0, sizeof(pre));
for(int i = 1; i <= n; i++)
if(!pre[i])
dfs(i);
}
int dp(int u)
{
if(d[u] != -1)
return d[u];
d[u] = cnt[u];
int ans = 0;
for(int i = 0; i < a[u].size(); i++)
{
int v = a[u][i];
int temp = dp(v);
ans = max(ans, temp);
}
d[u] += ans;
return d[u];
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
{
G[i].clear();
a[i].clear();
}
for(int i = 1; i <= m; i++)
{
int u, v;
scanf("%d %d", &u, &v);
G[u].push_back(v);
}
memset(degree, 0, sizeof(degree));
memset(cnt, 0, sizeof(cnt));
memset(d, -1, sizeof(d));
find_scc();
for(int u = 1; u <= n; u++)
{
for(int i = 0; i < G[u].size(); i++)
{
int v = G[u][i];
if(sccno[u] != sccno[v])
{
a[sccno[u]].push_back(sccno[v]);
degree[sccno[v]]++;
}
}
}
int ans = 0;
for(int i = 1; i <= scc_cnt; i++)
{
if(!degree[i])
{
int temp = dp(i);
ans = max(ans, temp);
}
}
printf("%d\n", ans);
}
return 0;
}