#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章