zoukankan      html  css  js  c++  java
  • Codeforces 1439B. Graph Subset Problem (思维,复杂度分析)

    题意

    给出一张无向图,让你找出一个大小为\(k\)的子团或者找出一个导出子图,使得图中的每个点的度数至少为\(k\)

    思路

    首先有个重要观察,当\(\frac{k(k-1)}{2} > m\)时,无解,因为无论是满足要求子团还是导出子图至少有\(\frac{k(k-1)}{2}\)条边,于是我们把\(k\)降到了\(O(\sqrt{m})\)的级别。

    对于导出子图,我们用类似拓扑序的方法一次将度数\(<k\)的点删去,剩下的点就是所求导出子图。当我们从队列中取出一个度数是\(k-1\)的点的时候,我们暴力判断这先连到的点是否是完全图,复杂度\(O(k^2)\)\(O(k^2logn)\),取决于实现,每次我们判断一个这样的完全图,就会删掉这\(k-1\)条边,于是最多只会做\(\frac{m}{k-1}\)次,于是复杂度是\(O(\frac{m}{k-1}) \cdot O(k^2) = O(mk) = O(m\sqrt m)\)

    代码

    #include<bits/stdc++.h>
    #define ll long long
    #define N 100015
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define per(i,a,n) for (int i=n;i>=a;i--)
    #define inf 0x3f3f3f3f
    #define pb push_back
    #define mp make_pair
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define lowbit(i) ((i)&(-i))
    #define VI vector<int>
    #define all(x) x.begin(),x.end()
    using namespace std;
    int t,n,m,k,in[N],vis[N],gkp[N];
    queue<int> q;
    VI e[N],cli;
    int main(){
    	//freopen(".in","r",stdin);
    	//freopen(".out","w",stdout);
     	scanf("%d",&t);
     	while(t--){
     		scanf("%d%d%d",&n,&m,&k);
     		while(!q.empty()) q.pop();
     		rep(i,1,n) e[i].clear(),in[i] = vis[i] = gkp[i] = 0;
     		rep(i,1,m){
     			int u,v; scanf("%d%d",&u,&v);
     			e[u].pb(v); e[v].pb(u);
     			in[u]++;in[v]++;
     		}
     		int tot = n;
     		if(k*(k-1) > 2*m) {puts("-1"); continue;}
     		rep(i,1,n) if(in[i] < k) q.push(i);
     		rep(i,1,n) sort(all(e[i]));
     		while(!q.empty()){
     			int u = q.front(); q.pop();
     			if(vis[u]) continue;
     			tot--;
     			vis[u] = 1;
     			if(in[u] == k-1){
    				cli.clear(); cli.pb(u);
    				for(auto x:e[u]){
    					if(vis[x]) continue;
    					cli.pb(x);
    				}
    				bool ff = 0;
    				for(auto p:cli){
    					for(auto q:cli){
    						if(p == q) continue;
    						if(!binary_search(all(e[p]),q)){
    							ff = 1; break;
    						}
    					}
    				}
    				if(ff == 0){
    					puts("2");
    					for(auto x:cli) printf("%d ",x);
    					printf("\n");
    					goto fuckyou;
    				}
    			}
    			vis[u] = 1;
     			for(auto v:e[u]){
     				in[v]--;
     				if(vis[v]) continue;
     				if(in[v] < k) q.push(v);
     			}
     		}
     		if(tot > 0){
     			printf("%d %d\n",1,tot);
     			rep(i,1,n) if(!vis[i]) printf("%d ",i);
     			printf("\n");
     		}else puts("-1");
     		fuckyou: continue;
     	}
    	return 0;
    }
    /*
    1
    2 1 2
    1 2
    */
    
  • 相关阅读:
    [Kali_Debian] 清除无用的库文件(清理系统,洁癖专用)-布布扣-bubuko.com
    给 Linux 系统“减肥”,系统垃圾清理_系统安装与配置管理_Linux Today
    命令行选项
    SQL 优化
    精通initramfs构建step by step
    常用正则表达式
    Chrome_浏览器开发人员工具
    按键精灵
    CMD命令大全
    50种折纸方法
  • 原文地址:https://www.cnblogs.com/czdzx/p/14017480.html
Copyright © 2011-2022 走看看