[CSP-S模拟测试]:Graph(图论+贪心)

题目描述

  给定一张$n$个点$m$条边的无向图,每条边连接两个顶点,保证无重边自环,不保证连通你想在这张图上进行若干次旅游,每次旅游可以任选一个点$x$作为起点,再走到一个与 $x$直接有边相连的点$y$,再走到一个与$y$直接有边相连的点$z$并结束本次旅游

  作为一个旅游爱好者,你不希望经过任意一条边超过一次,注意一条边不能即正向走一次又反向走一次,注意点可以经过多次,在满足此条件下,你希望进行尽可能多次的旅游,请计算出最多能进行的旅游次数并输出任意一种方案


输入格式

第$1$行两个正整数$n$与$m$,表示全图的点数与边数
下接$m$行,每行两个数字$u$与$v$表示一条边


输出格式

第$1$行一个整数$cnt$表示答案
下接$cnt$行,每行三个数字$x,y$与$z$,表示一次旅游的路线
如有多种旅行方案,任意输出一种即可


样例

样例输入:

4 5
1 2
3 2
2 4
3 4
4 1

样例输出:

2
4 1 2
4 3 2


数据范围与提示

对于前$20\%$的数据,$n\leqslant 10,m\leqslant 20$
对于令$20\%$的数据,$m=n−1$,并且图连通
对于令$10\%$的数据,每个点的度数不超过$2$
对于$100\%$的数据,$n\leqslant 100,000,m\leqslant 200,000$


题解

如果你做过下面这两道题的其中一道,这道题就会显得简单多了:

  $\alpha.$虎。

  $\beta.w$。

题不一样,但是思路是类似的。

对于树和链,我们显然是从叶子节点开始一定最优。

那么考虑一般情况,利用上面那两道题的思路(尤其是虎),也有点类似无修支配树,总之都是贪心……

时间复杂度:$\Theta(n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[400001];
struct node{int x,y,z;};
int head[100001],cnt=1;
int n,m;
int depth[100001];
vector<node> ans;
void add(int x,int y)
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
int dfs(int x)
{
	int res=0;
	for(int i=head[x];i;i=e[i].nxt)
	{
		if(!depth[e[i].to])
		{
			depth[e[i].to]=depth[x]+1;
			int flag=dfs(e[i].to);
			if(flag)ans.push_back((node){flag,e[i].to,x});
			else
			{
				flag=e[i].to;
				if(res){ans.push_back((node){flag,x,res});res=0;}
				else res=flag;
			}
		}
		else
		{
			if(depth[e[i].to]>depth[x])
			{
				int flag=e[i].to;
				if(flag)
				{
					if(res){ans.push_back((node){flag,x,res});res=0;}
					else res=flag;
				}
			}
		}
	}
	return res;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	for(int i=1;i<=n;i++)
		if(!depth[i])
		{
			depth[i]=1;
			dfs(i);
		}
	printf("%d\n",ans.size());
	for(int i=0;i<ans.size();i++)printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].z);
	return 0;
}

rp++

posted @ 2019-10-07 07:27  HEOI-动动  阅读(239)  评论(0编辑  收藏  举报