#649 (Div. 2)D. Ehab‘s Last Corollary

题目描述

Given a connected undirected graph with n vertices and an integer k, you have to either:
either find an independent set that has exactly ⌈k2⌉ vertices.
or find a simple cycle of length at most k.
An independent set is a set of vertices such that no two of them are connected by an edge. A simple cycle is a cycle that doesn’t contain any vertex twice.
I have a proof that for any input you can always solve at least one of these problems, but it’s left as an exercise for the reader.

Input

The first line contains three integers n, m, and k (3≤k≤n≤105, n−1≤m≤2⋅105) — the number of vertices and edges in the graph, and the parameter k from the statement.
Each of the next m lines contains two integers u and v (1≤u,v≤n) that mean there’s an edge between vertices u and v. It’s guaranteed that the graph is connected and doesn’t contain any self-loops or multiple edges.

Output

If you choose to solve the first problem, then on the first line print 1, followed by a line containing ⌈k2⌉ distinct integers not exceeding n, the vertices in the desired independent set.
If you, however, choose to solve the second problem, then on the first line print 2, followed by a line containing one integer, c, representing the length of the found cycle, followed by a line containing c distinct integers not exceeding n, the vertices in the desired cycle, in the order they appear in the cycle.

Examples

input
4 4 3
1 2
2 3
3 4
4 1
output
1
1 3
input
4 5 3
1 2
2 3
3 4
4 1
2 4
output
2
3
2 3 4
input
4 6 3
1 2
2 3
3 4
4 1
1 3
2 4
output
2
3
1 2 3
input
5 4 5
1 2
1 3
2 4
2 5
output
1
1 4 5

Note

In the first sample:
在这里插入图片描述
Notice that printing the independent set {2,4} is also OK, but printing the cycle 1−2−3−4 isn’t, because its length must be at most 3.
In the second sample:
在这里插入图片描述
Notice that printing the independent set {1,3} or printing the cycle 2−1−4 is also OK.
In the third sample:
在这里插入图片描述
In the fourth sample:
在这里插入图片描述

题目分析

有两种情况:

  1. 图为树时(即图中没有环时)
    此时可以用两个独立集来分别记录树中的点,如果某个点在a[0][]中,那么与它相邻的点都在a[1][]中。
    因为n>k,所以两个独立集必定至少有一个中含有至少(k+1)/2个点,因此该问题必定有解。最后输出某个独立集中(k+1)/2个点即可。
  2. 图不为树时(即图中有环时)
    这样就需要找环了,我们可以用deep[i]数组记录第i个点的深度(方便找环的长度),用pre[i]数组记录第i个点的父节点(方便保存路径从而进行回溯找点)。pos表示找到的环的最后一个位置。
    我们可以用dfs来进行搜索,当u的某个子节点的深度不为0时,就说明从u到该子节点形成了一个闭合的环,这个环的点数即为两点深度的差+1。
    1)当最小环的点数minv小于等于k时
    那么答案即为方案2,从pos位置开始,回溯k次即可。
    2)当最小环的点数minv大于k时
    那么答案为方案1,从pos位置开始,回溯(k+1)/2次即可(每次输出要往后回溯两次)。
代码如下
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <map>
#include <unordered_map>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#include <iomanip>
#define LL long long
using namespace std;
const int N=1e5+5;
int n,m,k;
vector<int> h[N];	//邻接表存图
vector<int> a[2];	//独立集
int minv=1e9,pos;
int pre[N],deep[N];
void DFS(int u,int fa,int de)	//图为树的情况
{
	a[de%2].push_back(u);
	for(int it:h[u])
	{
		if(it==fa) continue;
		DFS(it,u,(de+1)%2);
	}
}
void dfs(int u,int fa,int de)	//图非树的情况
{
	pre[u]=fa;
	deep[u]=de;
	for(int it:h[u])
	{
		if(it==fa) continue;
		if(deep[it])	//如果u的字节的的深度不为0
		{	//查看该环是否合法/该环的点数是否小于当前最小值
			if(deep[u]-deep[it]>0&&deep[u]-deep[it]+1<minv)
			{
				minv=deep[u]-deep[it]+1;
				pos=u;		//记录这个最后位置
			}
		}
		else dfs(it,u,de+1);
	}
}
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	for(int i=0;i<m;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		h[a].push_back(b);
		h[b].push_back(a);
	}
	if(m==n-1)		//当m==n-1时,图为树
	{
		DFS(1,-1,0);
		if(a[0].size()<a[1].size())
			swap(a[0],a[1]);
		
		puts("1");
		int t=(k+1)/2;
		for(int i=0;i<t;i++)
		{
			printf("%d ",a[0][i]);
		}
	}
	else	//否则图为非树
	{
		dfs(1,-1,1);
		if(minv<=k)	//1)的情况
		{
			puts("2");
			cout<<minv<<endl;
			while(minv--)
			{
				printf("%d ",pos);
				pos=pre[pos];
			}
		}
		else	//2)的情况
		{
			puts("1");
			int t=k+1>>1;
			while(t--)
			{
				printf("%d ",pos);
				pos=pre[pos];
				pos=pre[pos];
			}
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章