本题链接
题意:
给一个无向图,在图中找一个子图:
1.这个子图中每个点都连接 >= k条边
2.子图为k个点的完全图
思路:
对于每个点的子集,根据度数排序,通过标记法把度数小于k的点删除, 如果度数为k-1,判断与其相连的点是否能构成完全图,如果能则符合的2,输出答案。 否则删掉,最后判断剩余的度数大于等于k的点的个数是否存在,不存在输出-1。
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
const int maxn = 1e5 + 7;
vector<int> G[maxn], clique;
int d[maxn], n, vis[maxn], vis1[maxn];
void deal(int k){
queue<int> q;
for (int i = 1; i <= n; i ++ ){
if (d[i] < k){
q.push(i);
vis[i] = 1;
}
}
bool flag = false;
while (!q.empty()){
int u = q.front();
q.pop();
vis[u] = 1;
if (d[u] == k - 1){ // 找k个点的完全图
clique.clear();
clique.push_back(u);
for (int i = 0; i < G[u].size(); i ++ ){
int v = G[u][i];
if (vis1[v]) continue;
clique.push_back(v);
}
bool tem = false;
for (int i = 0; i < clique.size(); i ++ ){
for (int j = 0; j < clique.size(); j ++ ){
if (clique[i] == clique[j]) break;
//在数组中以二分法检索的方式查找,若在数组(要求数组元素非递减)中查找到indx元素则真,若查找不到则返回值为假。
if (!binary_search(G[clique[i]].begin(), G[clique[i]].end(), clique[j])){
tem = true;
}
}
}
if (!tem){
flag = true;
break;
}
clique.clear();
}
vis1[u] = 1;
for (int i = 0; i < G[u].size(); i ++ ){
int v = G[u][i];
d[v] --;
if (vis[v]) continue;
if (d[v] < k){
vis[v] = 1;
q.push(v);
}
}
}
if(flag){
printf ("2\n");
for (int i = 0; i < clique.size(); i ++ )
printf ("%d ", clique[i]);
}
else {
int cnt = 0;
for (int i = 1; i <= n; i ++ )
if (!vis[i]) cnt ++;
if (cnt > 0){
printf ("1 %d\n", cnt);
for (int i = 1; i <= n; i ++ ){
if (!vis[i]) printf ("%d ", i);
}
}
else printf ("-1");
}
printf ("\n");
}
void Init(){
for (int i = 1; i <= n; i ++ ){
G[i].clear();
vis[i] = vis1[i] = 0;
d[i] = 0;
}
}
int main (){
int T;
scanf ("%d", &T);
while (T -- ){
int m, k;
scanf ("%d%d%d", &n, &m, &k);
Init();
for (int i = 1, u, v; i <= m; i ++ ){
scanf ("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
if (k * (k - 1) > 2 * m){ // k完全图必要边数
printf ("-1\n");
continue;
}
for (int i = 1; i <= n; i ++ ){
d[i] = G[i].size();
sort(G[i].begin(), G[i].end());
}
deal(k);
}
return 0;
}