Codeforces Round #649 (Div. 2) D. Ehab's Last Corollary
题意:
给一个无向图,不含重边和自环,现在给出一个整数 \(k\) ,现在有两个问题:
- 在图中找到大小为 \(\lceil \frac{k}{2} \rceil\) 的独立点集;
- 在图中找到长度不超过 \(k\) 的环;
其中独立点集即集合中任意两点之间没有边;给出的无向图至少满足上面两种情况之一,现在要求你解决其中一个问题(自选),并输出具体答案,问题 \(1\) 输出独立点集,问题 \(2\) 按顺序输出环;
分析:
\(dfs\) 的同时用递归深度做权值判断每个环的大小,找到符合问题 \(2\) 的环就直接输出结束程序,否则随便找个点开始构建独立点集就好了;
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define frep(i,a,b) for(int i=a;i>=b;i--)
const int N = 1E5+10;
vector<int>G[N];
int n,k,m,lev[N],pt[N],cnt=0,vis[N];
void dfs(int u,int pre)
{
pt[++cnt]=u; //当前递归深度为cnt的节点
lev[u]=cnt; //节点u的递归深度
for(int v:G[u])
{
if(v==pre) continue;
if(!lev[v]) dfs(v,u); //节点v没有访问过,就继续dfs
//否则,那么节点v-u构成一个环,长度为lev[u]-lev[v]+1
else if(lev[u]-lev[v]+1>=0&&lev[u]-lev[v]+1<=k)
{
cout<<2<<endl<<lev[u]-lev[v]+1<<endl;
for(int i=lev[v];i<=lev[u];i++)
cout<<pt[i]<<" ";
exit(0);
}
}
/*
如果这个点没有被标记过,那么它就是独立点集之一,并把所有相邻的点标记;
这里相当于dfs到最深处然后反向构建独立点集,理由是保证了所有只有一个边
的点都被选进独立点集,这样的选择总是最优的
*/
if(!vis[u])
for(auto v:G[u]) vis[v]=1;
--cnt;
}
int main()
{
//freopen("1.txt","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
rep(i,1,m){
int u,v;
cin>>u>>v;
G[u].pb(v);
G[v].pb(u);
}
dfs(1,0);
k=(k+1)/2;
cout<<1<<endl;
rep(i,1,n)if(!vis[i]){
cout<<i<<" ";
if(--k==0) break;
}
}