ACWING 1175 最大半连通子图

ACWING 1175 最大半连通子图

缩点 + DAG DP

1175. 最大半连通子图 - AcWing题库

  1. 因为一个强连通分量中所有点可互相到达,所以一个强连通分量必然是一个半联通子图
  2. 缩点后,求最长链即可(此处的最长指链上的强连通分量中的点数之和最多)
  3. 因为已经是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;
}

posted @ 2022-05-18 15:32  hzy0227  阅读(7)  评论(0编辑  收藏  举报