ACWING 1175 最大半连通子图
缩点 + DAG DP
1175. 最大半连通子图 - AcWing题库
- 因为一个强连通分量中所有点可互相到达,所以一个强连通分量必然是一个半联通子图
- 缩点后,求最长链即可(此处的最长指链上的强连通分量中的点数之和最多)
- 因为已经是DAG,所以求最长链及方案数 dp 即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
int n, m, mod;
vector<int> G[N], E[N];
int tin[N], tim;
int scc_cnt, sz[N], id[N], low[N];
bool in_stk[N];
stack<int> stk;
set<PII> st;
ll f[N], g[N];
void add(int a, int b)
{
G[a].push_back(b);
}
void tarjan(int u)
{
tin[u] = low[u] = ++tim;
stk.push(u);
in_stk[u] = true;
for (int v : G[u])
{
if (!tin[v])
{
tarjan(v);
low[u] = min(low[u], low[v]);
}
else if (in_stk[v])
low[u] = min(low[u], tin[v]);
}
if (tin[u] == low[u])
{
++scc_cnt;
int y;
do
{
y = stk.top();
stk.pop();
in_stk[y] = false;
id[y] = scc_cnt;
sz[scc_cnt]++;
}while(y != u);
}
}
int main()
{
scanf("%d%d%d", &n, &m, &mod);
while(m--)
{
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
}
for (int i = 1; i <= n; i++)
if (!tin[i])
tarjan(i);
for (int u = 1; u <= n; u++)
{
for (int v : G[u])
{
int a = id[u], b = id[v];
if (a != b && !st.count({a, b}))
{
E[a].push_back(b);
st.insert({a, b});
}
}
}
for (int u = scc_cnt; u >= 1; u--)
{
if (!f[u])
{
f[u] = sz[u];
g[u] = 1;
}
for (int v : E[u])
{
if (f[v] < f[u] + sz[v])
{
f[v] = f[u] + sz[v];
g[v] = g[u];
}
else if (f[v] == f[u] + sz[v])
g[v] = (g[v] + g[u]) % mod;
}
}
ll sum = 0, maxn = 0;
for (int i = 1; i <= scc_cnt; i++)
{
if (f[i] > maxn)
{
maxn = f[i];
sum = g[i];
}
else if (f[i] == maxn)
sum = (sum + g[i]) % mod;
}
printf("%lld\n%lld\n", maxn, sum);
return 0;
}