题意:给定一张n个点m条边的无向图,每条边连接两个顶点,保证无重边自环,不保证连通
你想在这张图上进行若干次旅游,每次旅游可以任选一个点x作为起点,再走到一个与x 直接有边相连的点y,再走到一个与y 直接有边相连的点z 并结束本次旅游
作为一个旅游爱好者,你不希望经过任意一条边超过一次,注意一条边不能即正向走一次又反向走一次,注意点可以经过多次,在满足此条件下,你希望进行尽可能多次的旅游,请计算出最多能进行的旅游次数并输出任意一种方案
n<=2e5.
没看空间,无脑写了个1e5,挂成暴力,爽翻。
并不难的一道题(雾)。
首先把原图看作树形图,然后进行处理。
既然是一颗树,那么情况无非两种,一种是一条链,另外一种是山峰型。
为了保证最大化答案,我们从下往上开始填。
对于当前的一对点x,v,v为x的儿子,设这两个点和另外一个点z匹配成为答案。
由于从下往上匹配,保证z的深度比x小,等于v或者是v的儿子。
那么我们对于两种情况分开计算。
记录一个k,表示将要匹配的第三个点。
对于一个峰型点对,如果未能匹配成功,k记录v的兄弟。
对于一个链型点对,如果未能匹配成功,k记录v的儿子。
递归dfs返回k,即如果当前点未能匹配,能和当前点一起和匹配祖先的点。
如果v是已经走过的儿子,看看能否和k,x匹配,不可以的话就k=v,原理同上。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=5e5+5;
int n,m;
int head[N],next[N],go[N];
int dep[N],cnt,ans[4][N];
int tot;
inline int dfs(int x,int fa)
{
dep[x]=dep[fa]+1;int k=0;
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (!dep[v])
{
int z=dfs(v,x);
if (z)
{
ans[1][++cnt]=z;
ans[2][cnt]=v;
ans[3][cnt]=x;
}
else
{
z=v;
if (k)
{
ans[1][++cnt]=z;
ans[2][cnt]=x;
ans[3][cnt]=k;
k=0;
}
else k=z;
}
}
else
if (dep[v]>dep[x])
{
int z=v;
if (z)
{
if (k)
{
ans[1][++cnt]=z;
ans[2][cnt]=x;
ans[3][cnt]=k;
k=0;
}
else k=z;
}
}
}
return k;
}
inline void add(int x,int y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
int main()
{
scanf("%d%d",&n,&m);
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
fo(i,1,n)if (!dep[i])dfs(i,i);
printf("%d\n",cnt);
fo(i,1,cnt)printf("%d %d %d\n",ans[1][i],ans[2][i],ans[3][i]);
return 0;
}