题解:P11762 [IAMOI R1] 走亲访友

更差的阅读体验


如果原图是欧拉图,我们显然是会做的。我们可以先钦定哪些边是树边,然后在跑欧拉回路的过程中,直接删除非树边。这样我们就可以做到路径长度 \(\le m\),非常优秀。

那我们不妨将其推广,由于一条边可以通过多次,因此我们可以进行转换,将经过多次的边转换成重边,然后让每条边通过一次。

那么问题就转化成给定一个图,通过添加 \(\le n\) 条重边使其成为欧拉图。

那么我们考虑先将一棵生成树拎出来,然后从下往上递推,如果当前节点度数为奇数,就添加一条连往其父亲的边。因为这个时候父亲是还没有处理的,而父亲注定可以通过同样的调整满足欧拉图的条件。

那么这道题就做完了,时间复杂度显然是 \(O(n+m)\),而每个点最多只会多连一条边(\(s\) 不会向上连边),因此最后欧拉图的边数 \(\le n+m-1\),可以通过。

#include<bits/stdc++.h>
//#define int long long
#define endl '\n'
#define N 1006
using namespace std;
int n,m,tot,te[N*N],deg[N],vis[N],flag[N*N],K,s;
struct Tuple{int x,y,z;};
vector<Tuple> G[N];
//vector<tuple<int,int,int> > G[N];
vector<pair<int,int> > ans;
void dfs1(int u)
{
    vis[u]=1;vector<Tuple> tmp;
    for(auto [v,id,opt]:G[u])if(!vis[v]&&opt<=m)
    {
        dfs1(v),te[id]=1;
        if(deg[v]&1)
        {
            tmp.push_back({v,id,++tot});
            G[v].push_back({u,id,tot});
            deg[u]++,deg[v]++;
        }
    }
    for(auto t:tmp)G[u].push_back(t);
    tmp.clear();
}
void dfs2(int u)
{
    for(auto [v,id,opt]:G[u])if(!flag[opt])
    {
        flag[opt]=1;
        dfs2(v);
        ans.push_back({id,1});
    }
}
main()
{
    scanf("%d%d%d%d",&n,&m,&K,&s),tot=m;
    for(int i=1,u,v;i<=m;i++)
    {
        scanf("%d%d",&u,&v),deg[u]++,deg[v]++;
        G[u].push_back({v,i,i}),G[v].push_back({u,i,i});
    }
    dfs1(s),dfs2(s);
    reverse(ans.begin(),ans.end());
    for(int i=ans.size()-1;~i;i--)
    {
        if(te[ans[i].first])continue;
        if(flag[ans[i].first]==2)continue;
        ans[i].second=0,flag[ans[i].first]=2;
    }
    printf("%d\n",(int)ans.size());
    for(auto [id,opt]:ans)printf("%d %d\n",id,opt);
    return 0;
}
posted @   dyc2022  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
/* 设置动态特效 */ /* 设置文章评论功能 */ 返回顶端 levels of contents
点击右上角即可分享
微信分享提示