1439B Graph Subset Problem(求大小为k的团)
Codeforces Round #684 (Div. 2)
D. Graph Subset Problem
题意:有一张 n n n 个点 m m m 条边的图,给一个整数 k k k,问图中是否存在大小为 k k k 的团,或者是否存在一个点集,该点集中的每个点都至少有 k k k 个邻点在该点集中。如果两者都存在,输出任意一个,否则输出 -1。
范围: 1 ≤ t ≤ 1 e 5 , 1 ≤ n , m , k ≤ 1 e 5 , k ≤ n 1\le t \le 1e5,~1 \le n, m,k \le 1e5,~k \le n 1≤t≤1e5, 1≤n,m,k≤1e5, k≤n。
保证不存在自环和重边,所有 case 的 n n n 的总和与 m m m 的总和均不超过 2 e 5 2e5 2e5。
分析: 显然大小为 k k k 的团中边的数量为 k ( k − 1 ) 2 \frac{k(k-1)}{2} 2k(k−1),小于 g o o d s u b s e t good~subset good subset 所需要的边数,因此若 k ( k − 1 ) 2 > m \frac{k(k-1)}{2} > m 2k(k−1)>m,那么答案一定不存在,直接返回 -1。
根据上面的分析可以将该问题中 k k k 的范围从 1 e 5 1e5 1e5 降低为 2 m \sqrt{2m} 2m。
由于需要考虑每个点的邻点数量,容易想到从点的度入手,假设当前的图中度最小的点为 u u u,那么有三种情况:
① d e g [ u ] ≥ k deg[u] \ge k deg[u]≥k,此时图中剩下的点集必然形成 g o o d s u b s e t good~subset good subset。
② d e g [ u ] < k − 1 deg[u] < k - 1 deg[u]<k−1,该点不可能成为 大小为 k k k 的团 或者 g o o d s u b s e t good~subset good subset 中的点,直接将该点以及与该点相连的边删除,更新邻点的 d e g deg deg,继续取出图中度最小的点进行判断。
③ d e g [ u ] = = k − 1 deg[u] == k-1 deg[u]==k−1,考虑该点以及其邻点所形成的点集是否为大小为 k k k 的团,这里可以暴力对该点集中的点进行两两枚举,例如 a a a 和 b b b,通过二分(使用 unordered_map 更优)来判断 a a a 的邻点中是否存在 b b b,如果使用二分的话需要先对每个点的邻点进行排序,如果都满足条件说明找到了大小为 k k k 的团,输出答案。
复杂度分析:显然复杂度瓶颈在于判断图中是否存在大小为 k k k 的团,由于边数限制,满足 d e g [ u ] = = k − 1 deg[u] == k - 1 deg[u]==k−1 的点不会超过 m k − 1 \frac{m}{k-1} k−1m 个,进行一次暴力判断需要 O ( k 2 l o g n ) O(k^2logn) O(k2logn),因此总体时间复杂度为 O ( m k ∗ k 2 ∗ l o g n ) = O ( m k l o g n ) = O ( m m l o g n ) O(\frac{m}{k} * k^2*logn) = O(mklogn) = O(m\sqrt{m}logn) O(km∗k2∗logn)=O(mklogn)=O(mmlogn),若使用 unordered_map 则复杂度为 O ( m m ) O(m\sqrt{m}) O(mm)。
Code
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 1e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, m, k;
vector<int> E[MAXN], temp;
int vis[MAXN], inEdge[MAXN];
struct Node
{
int deg, idx;
bool operator < (const Node &other) const
{
if (deg == other.deg) return idx < other.idx;
else return deg < other.deg;
}
};
set<Node> S;
void solve()
{
while (!S.empty())
{
Node node = *S.begin();
vis[node.idx] = 1;
if (node.deg >= k)
{
cout << 1 << " " << S.size() << endl;
for (auto it = S.begin(); it != S.end(); it++)
{
if (it != S.begin()) cout << " ";
cout << (*it).idx;
}
cout << endl;
return;
}
else
{
if (node.deg == k - 1)
{
temp.clear();
int u = node.idx;
temp.push_back(u);
for (auto v : E[u])
{
if (vis[v]) continue;
temp.push_back(v);
}
int res = 1;
for (auto v : temp)
{
for (auto t : temp)
{
if (v == t) continue;
auto pos = lower_bound(E[v].begin(), E[v].end(), t);
if (pos == E[v].end() || *pos != t)
{
res = 0;
break;
}
}
if (!res) break;
}
if (res)
{
cout << 2 << endl;
for (int i = 0; i < temp.size(); i++)
{
if (i) cout << " ";
cout << temp[i];
}
cout << endl;
return;
}
}
S.erase(S.begin());
for (auto v : E[node.idx])
{
if (vis[v]) continue;
S.erase({inEdge[v], v});
S.insert({--inEdge[v], v});
}
}
}
cout << -1 << endl;
}
signed main()
{
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int T = read();
while (T--)
{
S.clear();
n = read(), m = read(), k = read();
for (int i = 0; i <= n; i++)
{
vis[i] = inEdge[i] = 0;
E[i].clear();
}
for (int i = 0; i < m; i++)
{
int u = read(), v = read();
E[u].push_back(v);
E[v].push_back(u);
inEdge[u]++, inEdge[v]++;
}
if (k * (k - 1) > 2 * m)
{
cout << -1 << endl;
continue;
}
for (int i = 1; i <= n; i++)
{
S.insert({inEdge[i], i});
sort(E[i].begin(), E[i].end());
}
solve();
}
return 0;
}
【END】感谢观看