Codeforces Round #684 (Div. 2) D Graph Subset Problem
D Graph Subset Problem
题意
给出一张 n n n点 m m m条边的无向图和一个数 k k k。
给出两个定义:
- c l i q u e clique clique:一个由 k k k个顶点及相互之间的边组成的子图,且为完全图。
- 给定条件的子图:每个顶点有大于等于 k k k个邻居。
问能否在图中找到上述之一的子图,若找到则输出子图的点,否则 − 1 -1 −1。
思路
首先根据数据量 n , m , k n,m,k n,m,k都是 e 5 e5 e5级别的数据,然后能隐隐感觉到数据之间的某些限制关系,能保证问题规模始终不会有想象中那么大,个人水平问题不会很严格的证明,证明可以参考官方题解。
如下只考虑具体做法。
首先我们只考虑第二类集合的求法,其实就是一般的拓扑排序的思想,对于无效点( d e g ≤ k − 1 deg \leq k-1 deg≤k−1),我们把这些点压入队列,然后 b f s bfs bfs删点删边并且更新无效点。然后剩余点的集合大小要是大于等于 k k k,那么剩余点集必然是第二类集合的答案集合。
考虑第一类集合的求法,即 c l i q u e clique clique的求法,首先压缩问题规模,显然只有在 k ∗ ( k − 1 ) ≤ 2 ∗ m k*(k-1) \leq 2 * m k∗(k−1)≤2∗m的时候才有可能存在 c l i q u e clique clique,这么一来就压缩了问题规模。那么首先,对于 c l i q u e clique clique的有效点只在上述求第二类集合的无效点的过程中产生( d e g = = k − 1 deg==k-1 deg==k−1),那么可以在第二类点的 t o p o topo topo过程中查找 c l i q u e clique clique,每遍历到一个 d e g = = k − 1 deg==k-1 deg==k−1的点,那么若想形成 c l i q u e clique clique,他所有没被遍历过的点必须压入 c l i q u e clique clique,如此反复,并且每一步都用暴力(二分)判断 c l i q u e clique clique内的点是否相互有边,若不能,那么之前的 c l i q u e clique clique无效。如此结束一次遍历,能保证若找到 c l i q u e clique clique内的都是第一类集合的有效点,即 c l i q u e clique clique非空即有解。
代码
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
int n, m, k;
vector<int> G[maxn];
int vis[maxn];
int deg[maxn];
inline void add(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; ++i) {
G[i].clear();
deg[i] = 0;
vis[i] = 0;
}
for (int i = 1; i <= m; ++i) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
++deg[u], ++deg[v];
}
for (int i = 1; i <= n; ++i) sort(G[i].begin(), G[i].end());
queue<int> q;
vector<int> clique;
for (int i = 1; i <= n; ++i) {
if (deg[i] < k) {
q.push(i), vis[i] = 1;
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 2; //说明已经被访问过
if (1ll * k * (k - 1) <= 2ll * m) {
if (deg[u] == k - 1 && clique.empty()) {
clique.push_back(u);
bool flag = 1;
for (auto v : G[u]) {
if (vis[v] != 2) clique.push_back(v);
}
int sz = clique.size();
for (int i = 0; i < sz; ++i) {
for (int j = i + 1; j < sz; ++j) {
if (!binary_search(G[clique[i]].begin(),
G[clique[i]].end(), clique[j])) {
flag = 0;
break;
}
}
}
if (!flag) clique.clear();
}
}
for (auto v : G[u]) {
--deg[v];
if (!vis[v] && deg[v] < k) {
vis[v] = 1;
q.push(v);
}
}
}
vector<int> res; //剩余点
for (int i = 1; i <= n; ++i) {
if (!vis[i]) res.push_back(i);
}
if (res.size() >= k) {
printf("1 %d\n", res.size());
for (auto w : res) {
printf("%d ", w);
}
puts("");
} else if (!clique.empty()) {
puts("2");
for (auto v : clique) {
printf("%d ", v);
}
puts("");
} else
puts("-1");
}
return 0;
}
上一篇: 爬虫入门(一)
推荐阅读
-
Codeforces Round #595 (Div. 3)D1D2 贪心 STL
-
Educational Codeforces Round 97 (Rated for Div. 2) D. Minimal Height Tree
-
Codeforces Round #665 (Div. 2) D. Maximum Distributed Tree(dfs)
-
构造思维+树形结构 Codeforces Round #612 (Div. 2) D题 Numbers on Tree
-
Codeforces Round #619 (Div. 2) D. Time to Run
-
Codeforces Round #583 (Div. 1 + Div. 2,) D. Treasure Island(dfs+思维)
-
Codeforces Round #320 (Div. 2) C. A Problem about Polyline ( 数学 )
-
Codeforces Round #533 (Div. 2) D. Kilani and the Game(bfs+模拟)
-
Codeforces Round #643 (Div. 2) D. Game With Array
-
Codeforces Round #564 (Div. 2) D - Nauuo and Circle(树上排列)