题解:P11811 [PA 2015] 人赢 / Mistrzostwa
为了解决这个问题,我们需要找到一个最大的连通点集,使得每个点的度数至少为 d,并且该点集的导出子图是连通的。我们可以通过以下步骤来实现:
方法思路
-
预处理阶段:首先计算每个节点的度数,并将度数小于d的节点进行拓扑排序式的删除。这些节点及其边会被逐步移除,直到所有剩余节点的度数都不小于 d。
-
连通分量查找:在剩余的节点中,使用
BFS查找最大的连通分量。这个连通分量即为满足条件的最大点集。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
vector<int> edge[N];
int l[N], in[N], vis[N];
int main() {
ios :: sync_with_stdio(false);
cin.tie(0);
int n, m, d;
cin >> n >> m >> d;
for (int i = 0; i < m; ++i) {
int u, v;
cin >> u >> v;
edge[u].push_back(v);
edge[v].push_back(u);
in[u]++;
in[v]++;
}
queue<int> q;
for (int u = 1; u <= n; ++u) {
if (in[u] < d) {
vis[u] = true;
q.push(u);
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : edge[u]) {
if (!vis[v]) {
in[v]--;
if (in[v] < d) {
vis[v] = true;
q.push(v);
}
}
}
}
memset(vis, 0, sizeof(vis));
for (int u = 1; u <= n; ++u) {
if (!vis[u] && !visited[u]) {
vector<int> c;
queue<int> Q;
Q.push(u);
visited[u] = true;
c.push_back(u);
while (!Q.empty()) {
int curr = Q.front();
Q.pop();
for (int v : edge[curr]) {
if (!vis[v] && !visited[v]) {
visited[v] = true;
c.push_back(v);
Q.push(v);
}
}
}
if (c.size() > l.size()) {
l = c;
}
}
}
if (l.empty()) {
cout << "NIE\n";
}
else {
sort(l.begin(), l.end());
cout << l.size() << '\n';
for (size_t i = 0; i < l.size(); ++i) {
cout << l[i] << (i + 1 < l.size() ? " " : "");
}
cout << '\n';
}
return 0;
}

浙公网安备 33010602011771号