Codeforces Round #649 (Div. 2) D

题意:

给一个无向图,不含重边和自环,现在给出一个整数 k k k ,现在有两个问题:

  1. 在图中找到大小为 ⌈ k 2 ⌉ \lceil \frac{k}{2} \rceil 2k 的独立点集;
  2. 在图中找到长度不超过 k k k 的环;

其中独立点集即集合中任意两点之间没有边;给出的无向图至少满足上面两种情况之一,现在要求你解决其中一个问题(自选),并输出具体答案,问题 1 1 1 输出独立点集,问题 2 2 2 按顺序输出环;

分析:

d f s dfs dfs 的同时用递归深度做权值判断每个环的大小,找到符合问题 2 2 2 的环就直接输出结束程序,否则随便找个点开始构建独立点集就好了;

代码:

#include
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;
	}
} 

你可能感兴趣的:(Codeforces Round #649 (Div. 2) D)