[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$
题解
如果你做过下面这两道题的其中一道,这道题就会显得简单多了:
题不一样,但是思路是类似的。
对于树和链,我们显然是从叶子节点开始一定最优。
那么考虑一般情况,利用上面那两道题的思路(尤其是虎),也有点类似无修支配树,总之都是贪心……
时间复杂度:$\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++