欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Codeforces Round #684 (Div. 2) D Graph Subset Problem

程序员文章站 2022-05-09 21:16:15
...

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 degk1),我们把这些点压入队列,然后 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(k1)2m的时候才有可能存在 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==k1),那么可以在第二类点的 t o p o topo topo过程中查找 c l i q u e clique clique,每遍历到一个 d e g = = k − 1 deg==k-1 deg==k1的点,那么若想形成 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