Codeforces Round #684 (Div. 2) D. Graph Subset Problem
原题链接:https://codeforces.com/contest/1440/problem/D
题意:
给你一张图,n个点,m条边,给定k,问能否找到下面两种图中任意一种。
- 找一个大小是k的集合,这k个点两两相连
- 找一个非空集合,里面每一个点都有至少k个点和他相连。
如果能找到第一种输出格式:
第一行输出2,第二行k个数表示这个k个点,顺序随意输出。
如果可以找到第二种输出格式:
第一行输出1和集合的大小len,第二行len个数,表示这个集合
第一种和第二种集合没有优先级,输出任意一个答案即可。
如果都没有找到则输出-1。
思路:
- 优先队列存放所有度数小于等于k-1的所有的点
- 如果度数==k-1,则讨论能否作为第一个的答案,可以则直接break
- 如果没有找到答案,那么这个点要把他连向的所有的点的度数都-1,并把这个点标记为已经访问过,重复第二个步骤
最后如果中途break了,那么就直接输出第一种答案即可,如果没有,那么判断最后是否还剩下点未被访问,如果有那么就说明这里的每一个点的度数都大于等于k,所以就找到第二种图的答案了,否则输出-1
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5+10; int in[maxn]; bool vis[maxn]; struct node{ int u; node(int u=0):u(u){} bool operator<(const node&a)const{ return in[a.u]<in[u]; } }; vector<int>G[maxn]; priority_queue<node>que; void init(int n){ while(!que.empty()) que.pop(); for(int i=1;i<=n;i++) { in[i] = 0,vis[i] = false; G[i].clear(); } } void add(int u,int v){ G[u].push_back(v); G[v].push_back(u); } vector<int>a; int main(){ int t; scanf("%d",&t); while(t--){ int n,m,k; scanf("%d%d%d",&n,&m,&k); init(n); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v); in[u]++,in[v]++; // printf("") } if(1ll*k*(k-1)>2*m){ printf("-1\n"); continue; } for(int i=1;i<=n;i++) { // printf("in[%d]=%d\n",i,in[i]); if(in[i]<k) que.push(i); sort(G[i].begin(),G[i].end()); } int ok = 0,now = n; while(!que.empty()){ int u = que.top().u;que.pop(); // printf("u = %d vis[%d]=%d in[%d]=%d\n",u,u,vis[u],u,in[u]); if(vis[u]) continue; if(in[u]==k-1){ a.clear(); int len = G[u].size(); for(int i=0;i<len;i++){ int v = G[u][i]; if(vis[v]) continue; a.push_back(v); } ok = u; len = a.size(); for(int i=0;i<len&&ok;i++){ for(int j=i+1;j<len&&ok;j++){ int l = a[i],r = a[j]; if(!binary_search(G[l].begin(),G[l].end(),r)){ ok = 0; break; } } } } if(ok) { a.push_back(u); break; } int len = G[u].size(); for(int i=0;i<len;i++){ int v = G[u][i]; if(vis[v]) continue; in[v]--; if(in[v]<k) que.push(v); } vis[u] = true; now--; } if(ok){ printf("2\n"); for(int i=0;i<k;i++){ printf("%d ",a[i]); } printf("\n"); } else if(now){ printf("1 %d\n",now); for(int i=1;i<=n;i++){ if(vis[i]) continue; printf("%d ",i); } printf("\n"); } else printf("-1\n"); } return 0; }