1 条题解
-
0
首先一定存在一个点度数 ,因为整张图也算它的一个导出子图。设这个点为 。实现上为了方便可以直接找度数最小的点。
把图中所有点集分成两种:包含 的和不包含 的。
对于包含 的团,显然其点数不超过 (不超过 的度数),于是先把这 个点拎出来。 枚举每个点选/不选,然后判断选出的能否构成团。
令 表示与 相邻的点构成的集合。那么 可以构成团,当且仅当 $\{i_1,i_2\dots,i_k\} \subseteq S_{i_1} \cap S_{i_2} \cap \dots \cap S_{i_k}$。
此时容易想到压位。把 中有用的 个位置取出,压到一个 的 int 中,求解所有掩码的与和即可。
这样包含 的最大团就算好了。在图中把 删去,重复上面过程即可。
删点用 set 实现会比较简单。总复杂度 。
#include <bits/stdc++.h> using namespace std; const int N = 5e4 + 10; int n, k, d[N]; set<int> g[N]; signed main() { cin >> n >> k; for (int i = 0; i < n; ++ i ) g[i].insert(i); for (int i = 0; i < n; ++ i ) { int cnt; cin >> cnt; d[i] = cnt + 1; while (cnt -- ) { int j; cin >> j; g[i].insert(j); } } int res = 0; set<pair<int, int>> S; for (int i = 0; i < n; ++ i ) S.insert({d[i], i}); while (S.size()) { int u = (*S.begin()).second; S.erase(S.begin()); vector<int> v, msk; v.push_back(u); for (int i : g[u]) { if (i != u) v.push_back(i); } int sz = g[u].size(); for (int i : v) { int res = 0; for (int j = 0; j < sz; ++ j ) { res |= g[i].count(v[j]) << j; } msk.push_back(res); } for (int s = 1; s < 1 << sz; s += 2) { int t = -1; for (int i = 0; i < sz; ++ i ) if (s >> i & 1) { t = t == -1 ? msk[i] : (t & msk[i]); } if ((s & t) == s) res = max(res, __builtin_popcount(s)); } for (int i : v) if (i != u) { g[i].erase(u); S.erase({d[i], i}); d[i] -- ; if (d[i] > 0) S.insert({d[i], i}); } } cout << res; return 0; }
- 1
信息
- ID
- 10558
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者