codeforces 858F&&JZOJ5404graph dfs

73 篇文章 0 订阅
7 篇文章 0 订阅

题意:给定一张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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值