2025.06.19 CW 模拟赛 C. 挑战 NPC

C. 挑战 NPC

题目描述

众所周知,一般图最大团问题是 NPC 问题。现在自命不凡的你要挑战它。
我们定义是每两个点都有边相连的点集,特别地,单独一个点也算作团。


思路

原题数据较水, 搜索配合剪枝即可通过.
关于「一般图最大团」问题可以使用 \(\text{Bron–Kerbosch}\) 算法, 但是对于这道题, 我们有更简洁的做法.

观察到 \(n \le 45\), 复杂度 \(\mathcal{O}(n 2^{\frac n 2})\)​ 的算法是可以通过的, 不难想到使用折半搜索.

具体而言, 折半搜索的一般流程为

  1. 将原序列分为两半, 分别进行搜索并记录状态.
  2. 合并两侧状态.

在这道题中, 第一步即先搜索出前一半所有能够成为团的点的集合, 再搜索出后一半能够成为团的点集.

考虑合并.
在第一步中, 我们将点集状压为一个二进制数 \(S\), 定义 \(f_S\) 表示 \(S\) 及它的子集中能够成为团的最大点数, 使用高维前缀和可以做到 \(\mathcal{O}(\frac n 2 \times 2^{\frac n 2})\)​.
合并时, 我们枚举后一半所有合法点集, 并记录其中所有点到前一半的边集与起来的值, 最后答案即为 \(\max\{\text{后一半点集大小} + f_{\text{边集与起来的值}}\}\).

复杂度 \(\mathcal{O}(\frac n 2 \times 2^{\frac n 2})\).

#include <iostream>
using namespace std;

typedef long long ll;

int n, m, mid, f[4194304];
ll pow2[45], e[45];

void pre() {
	pow2[0] = 1;
	for (int i = 1; i < 45; ++i) {
		pow2[i] = pow2[i - 1] + pow2[i - 1];
	}
}

void init() {
	cin >> n >> m;
	for (int i = 0; i < n; ++i) {
		e[i] = pow2[i];
	}
	for (int i = 1, u, v; i <= m; ++i) {
		cin >> u >> v, --u, --v;
		e[u] |= pow2[v], e[v] |= pow2[u];
	}
	
	mid = n / 2;
	for (int S = 0; S < pow2[mid]; ++S) {
		int T = pow2[mid] - 1;
		for (int i = 0; i < mid; ++i) {
			if (S >> i & 1) {
				T &= e[i];
			}
		}
		if ((S & T) == S) {
			f[S] = __builtin_popcount(S);
		}
		else {
			f[S] = 0;
		}
	}
	for (int S = 0; S < pow2[mid]; ++S) {
		for (int i = 0; i < mid; ++i) {
			if (S >> i & 1) {
				f[S] = max(f[S], f[S ^ pow2[i]]);
			}
		}
	}
}

void calculate() {
	int ans = 0;
	
	for (int S = 0; S < pow2[n - mid]; ++S) {
		ll Tbig = (pow2[n] - 1) ^ (pow2[mid] - 1);
		int Tsmall = pow2[mid] - 1;
		for (int i = 0; i < n - mid; ++i) {
			if (S >> i & 1) {
				Tbig &= e[mid + i], Tsmall &= e[mid + i];
			}
		}
		if ((S & (Tbig >> mid)) == S) {
			ans = max(ans, __builtin_popcount(S) + f[Tsmall]);
		}
	}
	cout << ans << '\n';
}

void solve() {
	cin.tie(nullptr)->sync_with_stdio(false);
	pre();
	int t;
	cin >> t;
	while (t--) {
		init(), calculate();
	}
}

int main() {
	solve();
	return 0;
}
posted @ 2025-06-19 19:39  Steven1013  阅读(12)  评论(0)    收藏  举报