Description
给定 (n) 个点的无向图和一个整数 (k le n),要求解决一下问题中的任何一个:求一个大小恰好为 (lceil frac n 2 ceil) 的独立集;求一个大小不超过 (k) 的环。已经可以证明对于任意给定的整数 (k) 一定可以解决这两个问题中的一个。
Solution
由于已经保证了对于任意给定的整数 (k) 一定可以解决这两个问题中的一个,我们不妨取 (k=n),此时如果原图是一棵树,那么我们直接二分图染色即可;否则,必然有一个长度不超过 (n) 的环。
考虑原问题,我们只需要找一个结点数为 (k) 的连通子图(由于原图是连通的所以我们一定能找到),对这个子图进行上面的求解即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
namespace subtask
{
vector <int> g[N];
int n,m,vis[N],col[N];
set <int> vec;
stack <int> sta;
vector <int> res;
void make(int p,int q)
{
g[p].push_back(q);
g[q].push_back(p);
++m;
if(vec.find(p)==vec.end()) vec.insert(p);
if(vec.find(q)==vec.end()) vec.insert(q);
}
void dfs1(int p)
{
vis[p]=1;
for(int q:g[p])
{
if(!vis[q])
{
col[q]=col[p]^1;
dfs1(q);
}
}
}
void dfs2(int p,int fa)
{
sta.push(p);
vis[p]=1;
for(int q:g[p])
{
if(!vis[q] && fa!=q)
{
dfs2(q,p);
}
else if(vis[q] && fa!=q)
{
res.push_back(q);
while(sta.top()!=q)
{
res.push_back(sta.top());
sta.pop();
}
cout<<res.size()<<endl;
for(int i:res) cout<<i<<" ";
cout<<endl;
exit(0);
}
}
sta.pop();
}
void solve()
{
if(n==m+1)
{
cout<<1<<endl;
int v0=*vec.begin();
dfs1(v0);
int cnt[2]={0,0};
for(int p:vec) cnt[col[p]]++;
int tot=(n+1)/2;
if(cnt[0]>cnt[1])
{
for(int p:vec)
{
if(col[p]==0) cout<<p<<" ", --tot;
if(tot==0) break;
}
}
else
{
for(int p:vec)
{
if(col[p]==1) cout<<p<<" ", --tot;
if(tot==0) break;
}
}
cout<<endl;
}
else
{
cout<<2<<endl;
int v0=*vec.begin();
dfs2(v0,0);
}
}
}
int n,m,k,t1,t2,t3,t4,vis[N],u[N];
vector <int> g[N];
vector <int> vec;
void dfs(int p)
{
vis[p]=1;
if(vec.size()==k) return;
vec.push_back(p);
for(int q:g[p])
{
if(!vis[q])
{
dfs(q);
}
}
}
signed main()
{
cin>>n>>m>>k;
for(int i=1;i<=m;i++)
{
int t1,t2;
cin>>t1>>t2;
g[t1].push_back(t2);
g[t2].push_back(t1);
}
dfs(1);
for(int i:vec) u[i]=1;
for(int i:vec)
{
for(int j:g[i])
{
if(u[j])
{
if(i<j) subtask::make(i,j);
}
}
}
subtask::n=k;
subtask::solve();
return 0;
}