CodeForces-1440D Graph Subset Problem

本题链接
题意:
给一个无向图,在图中找一个子图:
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值