• [CF1439B] Graph Subset Problem


    [题目链接]

    https://codeforces.com/contest/1439/problem/B

    [题解]

    首先若 (K > sqrt{2M}) , 必然无解。 这是因为无论是一个团还是一个度数均大于等于 (K) 的联通块 , 边数都比 (M) 更大。

    考虑 (deg(u) < K - 1) 的点 , 显然 , 这部分点可以直接删去 , 因为它们不可能出现在任何一个团或联通块中。

    考虑 (deg(u) = K - 1) 的点 , 对于这种情况 , 找出其所有相邻的点 , 将每个节点的邻接表到达的节点从小到大排序 , 那么对于每组点在邻接表内二分判断是否存在即可。

    而对于 (deg(u) geq K) 的点 , 这说明可以在一个度数均比 (K) 大的联通块中。 可以直接跳过。

    至此得到了一个类似于拓扑排序的算法。 这个问题得到了完美地解决。

    这个解法的复杂度瓶颈在于判断团的存在 , 因为最多判 (lfloor frac{M}{K} floor) 个团 , 所以时间复杂度 (O(frac{M}{K}) cdot O(K ^ 2) = O(MK) leq O(Msqrt{M}))

    [代码]

    #include <bits/stdc++.h>
     
    using namespace std;
     
    typedef long long LL;
     
    const int MN = 2e5 + 5;
     
    int N , M , K , vis[MN] , deg[MN];
    vector < int > g[MN];
     
    inline void solve() {
    	scanf("%d%d%d" , &N , &M , &K);
    	for (int i = 1; i <= N; ++i) {
    		vis[i] = 0;
    		g[i].clear();
    	}
    	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 - 1ll) > 2 * M) {
    		puts("-1"); return ;
    	}
    	for(int i = 1; i <= N; i ++) {
    		sort(g[i].begin(), g[i].end());
    		deg[i] = g[i].size();
    	}
    	queue<int> q;
    	for(int i = 1; i <= N; i ++) if(deg[i] < K) q.push(i), vis[i] = 1;
    	vector<int> clique;
    	while(q.size()) {
    		int u = q.front(); q.pop(); vis[u] = 2;
    		if(deg[u] == K - 1 && !clique.size()) {
    			vector<int> cur = {u};
    			for(int v : g[u]) if(2 ^ vis[v]) cur.push_back(v);
    			bool mark = 1;
    			for(int u : cur) for(int v : cur) if(u < v) {
    				if(!binary_search(g[u].begin(), g[u].end(), v)){
    					mark = 0; break ;
    				}
    			}
    			if(mark) clique = cur;
    		}
    		for(int v : g[u]) {
    			if(-- deg[v] < K && !vis[v]) {
    				vis[v] = 1; q.push(v);
    			}
    		}
    	}
    	if (count(vis + 1 , vis + N + 1 , 0)) {
    		vector < int > ans;
    		for (int i = 1; i <= N; ++i) if (!vis[i]) ans.push_back(i);
    		printf("1 %d
    " , (int) ans.size());
    		for (int v : ans) printf("%d " , v);
    		printf("
    ");
    	} else if (clique.size()) {
    		printf("2
    ");
    		for (int v : clique) printf("%d " , v);
    		printf("
    ");
    	} else printf("-1
    ");
    }
    int main() {
    	
    	int T; scanf("%d" , &T);
    	while (T--) solve();	
    	return 0;
    }
  • 相关阅读:
    悬崖边上的舞者,记7.2生产数据库灾难事件
    MySQL数据库辅助类
    C# 自定义控件VS用户控件
    WinForm创建自定义控件
    mvc导出excel
    aspose导出excel文件
    oracle 定义带参数的视图
    extjs 分组函数自定义统计
    向第三次世界大战中的勇士致敬
    Office2007打开文件提示“您尝试打开的文件xxx.xls的格式与文件扩展名指定的格式不一致”的解决办法
  • 原文地址:https://www.cnblogs.com/evenbao/p/14039515.html
Copyright © 2020-2023  润新知