P3450 Zos-Sophie
P3450 Zos-Sophie
更好的阅读体验
简要题意: 给出一个
数据规模:
题解: 图的最大独立集是个 NP 完全问题,但是数据给定了
考虑图上最大独立集的对偶问题,即图上最小点覆盖(用最少的点覆盖每一条边)。如此以来,问题转化为考虑用哪些点去覆盖所有的边。为了防止意义上的混淆,定义集合
算法
下面分析上述算法的时间复杂度。注意到每次操作必须删除至少
算法 NIE。考察剩余度数
引理
\text{I} : 如果图G 的所有点度数均\le l ,且最小点覆盖大小< l' ,则G 中的边数不超过l \times l' ,度数> 0 的点数不超过2\times l \times l' 。
证明显然,考虑每个点覆盖集合中的点都覆盖了
因此,在删完度数 NIE。这样图
代码有较多的细节,以及一些地方需要精细实现以保证复杂度。
注:随机化算法也能够通过此题,可以见 Claris 的博客。
spj 待修,如果管理员来审这篇题解了请看这个帖子。
代码:
using ll = long long;
const int N = 1e6 + 10, M = 3e6 + 10;
int n, m, k, sz, mp[N], deg[N];
bool del[N];
set<int> g[N], rec[N];
vector<int> ans;
pair<int, int> edg[M];
set<pair<int, int>> st;
bool check() {
vector<int> res;
for (int i = 1; i <= sz; ++i) {
if (!g[mp[i]].empty()) return false;
if (del[mp[i]]) res.push_back(mp[i]);
}
if (res.size() < ans.size() || (res.size() == ans.size() && res > ans))
ans = res;
return true;
}
bool dfs(int p, int cnt) {
if (cnt > k) return false;
if (check()) return true;
while (p <= sz && g[mp[p]].empty()) ++p;
if (p > sz) return false;
bool ret = false;
int u = mp[p]; set<int> adj = g[u];
for (auto v : adj) g[v].erase(u);
swap(g[u], rec[u]), del[u] = true;
ret |= dfs(p + 1, cnt + 1);
swap(g[u], rec[u]), del[u] = false;
for (auto v : adj) g[v].insert(u);
for (auto v : adj)
for (auto w : g[v]) g[w].erase(v);
for (auto v : adj)
swap(g[v], rec[v]), del[v] = true;
ret |= dfs(p + 1, cnt + adj.size());
for (auto v : adj)
swap(g[v], rec[v]), del[v] = false;
for (auto v : adj)
for (auto w : g[v]) g[w].insert(v);
return ret;
}
signed main() {
read(n), read(k), read(m), k = n - k;
for (int i = 1, u, v; i <= m; ++i)
read(u), read(v), edg[i] = minmax(u, v);
sort(edg + 1, edg + m + 1);
m = unique(edg + 1, edg + m + 1) - edg - 1;
for (int i = 1, u, v; i <= m; ++i)
tie(u, v) = edg[i], ++deg[u], ++deg[v];
for (int i = 1; i <= n; ++i)
if (deg[i] > k) --k, del[i] = true;
fill(deg + 1, deg + n + 1, 0);
for (int i = 1, u, v; i <= m; ++i) {
tie(u, v) = edg[i];
if (!del[u] && !del[v])
g[u].insert(v), g[v].insert(u);
}
for (int i = 1; i <= n; ++i)
if (!g[i].empty()) mp[++sz] = i;
ans.resize(sz);
if (sz > 2 * k * k || !dfs(1, 0)) return puts("NIE"), 0;
for (auto p : ans) del[p] = true;
ans.clear();
for (int i = 1; i <= n; ++i) if (!del[i]) ans.push_back(i);
write(ans.size()), putchar('\n');
for (int i = 0; i < (int)ans.size(); ++i)
write(ans[i]), putchar(" \n"[i == (int)ans.size() - 1]);
return 0;
}